Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
  //
  //  ========================================================================
  //  Copyright (c) 1995-2015 Mort Bay Consulting Pty. Ltd.
  //  ------------------------------------------------------------------------
  //  All rights reserved. This program and the accompanying materials
  //  are made available under the terms of the Eclipse Public License v1.0
  //  and Apache License v2.0 which accompanies this distribution.
  //
  //      The Eclipse Public License is available at
 //      http://www.eclipse.org/legal/epl-v10.html
 //
 //      The Apache License v2.0 is available at
 //      http://www.opensource.org/licenses/apache2.0.php
 //
 //  You may elect to redistribute this code under either of these licenses.
 //  ========================================================================
 //
 
 package org.eclipse.jetty.proxy;
 
 import java.net.URI;
 
 

Servlet 3.1 asynchronous proxy servlet.

Both the request processing and the I/O are asynchronous.

 
 public class AsyncProxyServlet extends ProxyServlet
 {
     private static final String WRITE_LISTENER_ATTRIBUTE = AsyncProxyServlet.class.getName() + ".writeListener";
 
     @Override
     protected ContentProvider proxyRequestContent(Request proxyRequestHttpServletRequest requestthrows IOException
     {
         ServletInputStream input = request.getInputStream();
         DeferredContentProvider provider = new DeferredContentProvider();
         input.setReadListener(newReadListener(proxyRequestrequestprovider));
         return provider;
     }
 
     protected ReadListener newReadListener(Request proxyRequestHttpServletRequest requestDeferredContentProvider provider)
     {
         return new StreamReader(proxyRequestrequestprovider);
     }
 
     @Override
     protected void onResponseContent(HttpServletRequest requestHttpServletResponse responseResponse proxyResponsebyte[] bufferint offsetint lengthCallback callback)
     {
         try
         {
             if (.isDebugEnabled())
                 .debug("{} proxying content to downstream: {} bytes"getRequestId(request), length);
             StreamWriter writeListener = (StreamWriter)request.getAttribute();
             if (writeListener == null)
             {
                 writeListener = newWriteListener(requestproxyResponse);
                 request.setAttribute(writeListener);
 
                 // Set the data to write before calling setWriteListener(), because
                 // setWriteListener() may trigger the call to onWritePossible() on
                 // a different thread and we would have a race.
                 writeListener.data(bufferoffsetlengthcallback);
 
                 // Setting the WriteListener triggers an invocation to onWritePossible().
                 response.getOutputStream().setWriteListener(writeListener);
             }
             else
             {
                 writeListener.data(bufferoffsetlengthcallback);
                 writeListener.onWritePossible();
             }
         }
         catch (Throwable x)
         {
             callback.failed(x);
             proxyResponse.abort(x);
         }
    }
    protected StreamWriter newWriteListener(HttpServletRequest requestResponse proxyResponse)
    {
        return new StreamWriter(requestproxyResponse);
    }

    

Convenience extension of AsyncProxyServlet that offers transparent proxy functionalities.

    public static class Transparent extends AsyncProxyServlet
    {
        private final TransparentDelegate delegate = new TransparentDelegate(this);
        @Override
        public void init(ServletConfig configthrows ServletException
        {
            super.init(config);
            .init(config);
        }
        @Override
        protected URI rewriteURI(HttpServletRequest request)
        {
            return URI.create(.rewriteTarget(request));
        }
    }
    protected class StreamReader extends IteratingCallback implements ReadListener
    {
        private final byte[] buffer = new byte[getHttpClient().getRequestBufferSize()];
        private final Request proxyRequest;
        private final HttpServletRequest request;
        private final DeferredContentProvider provider;
        protected StreamReader(Request proxyRequestHttpServletRequest requestDeferredContentProvider provider)
        {
            this. = proxyRequest;
            this. = request;
            this. = provider;
        }
        @Override
        public void onDataAvailable() throws IOException
        {
            iterate();
        }
        @Override
        public void onAllDataRead() throws IOException
        {
            if (.isDebugEnabled())
                .debug("{} proxying content to upstream completed"getRequestId());
            .close();
        }
        @Override
        public void onError(Throwable t)
        {
            onClientRequestFailure(t);
        }
        @Override
        protected Action process() throws Exception
        {
            int requestId = .isDebugEnabled() ? getRequestId() : 0;
            ServletInputStream input = .getInputStream();
            // First check for isReady() because it has
            // side effects, and then for isFinished().
            while (input.isReady() && !input.isFinished())
            {
                int read = input.read();
                if (.isDebugEnabled())
                    .debug("{} asynchronous read {} bytes on {}"requestIdreadinput);
                if (read > 0)
                {
                    if (.isDebugEnabled())
                        .debug("{} proxying content to upstream: {} bytes"requestIdread);
                    onRequestContent(, 0, readthis);
                    return .;
                }
            }
            if (input.isFinished())
            {
                if (.isDebugEnabled())
                    .debug("{} asynchronous read complete on {}"requestIdinput);
                return .;
            }
            else
            {
                if (.isDebugEnabled())
                    .debug("{} asynchronous read pending on {}"requestIdinput);
                return .;
            }
        }
        protected void onRequestContent(Request proxyRequestHttpServletRequest requestDeferredContentProvider providerbyte[] bufferint offsetint lengthCallback callback)
        {
            provider.offer(ByteBuffer.wrap(bufferoffsetlength), callback);
        }
        @Override
        public void failed(Throwable x)
        {
            super.failed(x);
            onError(x);
        }
    }
    protected class StreamWriter implements WriteListener
    {
        private final HttpServletRequest request;
        private final Response proxyResponse;
        private WriteState state;
        private byte[] buffer;
        private int offset;
        private int length;
        private Callback callback;
        protected StreamWriter(HttpServletRequest requestResponse proxyResponse)
        {
            this. = request;
            this. = proxyResponse;
            this. = .;
        }
        protected void data(byte[] bytesint offsetint lengthCallback callback)
        {
            if ( != .)
                throw new WritePendingException();
            this. = .;
            this. = bytes;
            this. = offset;
            this. = length;
            this. = callback;
        }
        @Override
        public void onWritePossible() throws IOException
        {
            int requestId = getRequestId();
            ServletOutputStream output = .getAsyncContext().getResponse().getOutputStream();
            if ( == .)
            {
                // There is data to write.
                if (.isDebugEnabled())
                    .debug("{} asynchronous write start of {} bytes on {}"requestIdoutput);
                output.write();
                 = .;
                if (output.isReady())
                {
                    if (.isDebugEnabled())
                        .debug("{} asynchronous write of {} bytes completed on {}"requestIdoutput);
                    complete();
                }
                else
                {
                    if (.isDebugEnabled())
                        .debug("{} asynchronous write of {} bytes pending on {}"requestIdoutput);
                }
            }
            else if ( == .)
            {
                // The write blocked but is now complete.
                if (.isDebugEnabled())
                    .debug("{} asynchronous write of {} bytes completing on {}"requestIdoutput);
                complete();
            }
            else
            {
                throw new IllegalStateException();
            }
        }
        protected void complete()
        {
             = null;
             = 0;
             = 0;
            Callback c = ;
             = null;
             = .;
            // Call the callback only after the whole state has been reset,
            // because the callback may trigger a reentrant call and
            // the state must already be the new one that we reset here.
            c.succeeded();
        }
        @Override
        public void onError(Throwable failure)
        {
            .abort(failure);
        }
    }
    private enum WriteState
    {
        READY, PENDING, IDLE
    }
New to GrepCode? Check out our FAQ X