package org.limewire.http.protocol; import java.io.IOException; import java.util.concurrent.Executor; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; import org.apache.http.ConnectionReuseStrategy; import org.apache.http.HttpResponse; import org.apache.http.HttpResponseFactory; import org.apache.http.impl.nio.DefaultNHttpServerConnection; import org.apache.http.nio.NHttpConnection; import org.apache.http.nio.NHttpServerConnection; import org.apache.http.nio.protocol.AsyncNHttpServiceHandler; import org.apache.http.nio.util.ByteBufferAllocator; import org.apache.http.nio.util.HeapByteBufferAllocator; import org.apache.http.params.HttpParams; import org.apache.http.protocol.ExecutionContext; import org.apache.http.protocol.HttpContext; import org.apache.http.protocol.HttpProcessor; import org.limewire.http.reactor.DefaultDispatchedIOReactor; import org.limewire.http.reactor.HttpIOSession; /** * An extension to {@link AsyncNHttpServiceHandler} to allow more fine-grained * control. */ public class ExtendedAsyncNHttpServiceHandler extends AsyncNHttpServiceHandler { public ExtendedAsyncNHttpServiceHandler( final HttpProcessor httpProcessor, final HttpResponseFactory responseFactory, final ConnectionReuseStrategy connStrategy, final ByteBufferAllocator allocator, final HttpParams params) { super(httpProcessor, responseFactory, connStrategy, allocator, params); } public ExtendedAsyncNHttpServiceHandler( final HttpProcessor httpProcessor, final HttpResponseFactory responseFactory, final ConnectionReuseStrategy connStrategy, final HttpParams params) { this(httpProcessor, responseFactory, connStrategy, new HeapByteBufferAllocator(), params); } public void setEventListener(final HttpServiceEventListener eventListener) { this.eventListener = eventListener; } @Override protected void responseComplete(HttpResponse response, HttpContext context) { NHttpServerConnection conn = (NHttpServerConnection) context .getAttribute(ExecutionContext.HTTP_CONNECTION); if(eventListener instanceof HttpServiceEventListener) { ((HttpServiceEventListener)eventListener).responseSent(conn, response); } if(conn.isOpen()) { final DefaultNHttpServerConnection c = (DefaultNHttpServerConnection)conn; // make sure any buffered requests are processed if (c.hasBufferedInput()) { HttpIOSession session = (HttpIOSession)c.getContext().getAttribute(DefaultDispatchedIOReactor.IO_SESSION_KEY); Executor executor = session.getIoExecutor(); Runnable runner = new Runnable() { public void run() { c.consumeInput(ExtendedAsyncNHttpServiceHandler.this); } }; // By scheduling, we can force it to execute _after_ this. // Otherwise, things running after this could erase state this sets. if(executor instanceof ScheduledExecutorService) { ((ScheduledExecutorService)executor).schedule(runner, 0, TimeUnit.MILLISECONDS); } else { executor.execute(runner); } } } } @Override protected void closeConnection(NHttpConnection conn, Throwable cause) { // Make sure outgoing connections are cleaned up. ServerConnState state = (ServerConnState)conn.getContext().getAttribute(CONN_STATE); try { state.finishOutput(); } catch(IOException ignored) {} super.closeConnection(conn, cause); } @Override protected void shutdownConnection(NHttpConnection conn, Throwable cause) { ServerConnState state = (ServerConnState)conn.getContext().getAttribute(CONN_STATE); try { state.finishOutput(); } catch(IOException ignored) {} super.shutdownConnection(conn, cause); } }