package org.limewire.http; import java.io.IOException; import java.net.InetSocketAddress; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import junit.framework.Test; import org.apache.http.HttpEntity; import org.apache.http.HttpHost; import org.apache.http.HttpRequest; import org.apache.http.HttpResponse; import org.apache.http.impl.DefaultConnectionReuseStrategy; import org.apache.http.impl.nio.DefaultClientIOEventDispatch; import org.apache.http.message.BasicHttpRequest; import org.apache.http.nio.NHttpConnection; import org.apache.http.nio.entity.BufferingNHttpEntity; import org.apache.http.nio.entity.ConsumingNHttpEntity; import org.apache.http.nio.protocol.AsyncNHttpClientHandler; import org.apache.http.nio.protocol.NHttpRequestExecutionHandler; import org.apache.http.nio.reactor.ConnectingIOReactor; import org.apache.http.nio.reactor.IOEventDispatch; import org.apache.http.nio.reactor.SessionRequest; import org.apache.http.nio.reactor.SessionRequestCallback; import org.apache.http.nio.util.HeapByteBufferAllocator; import org.apache.http.params.BasicHttpParams; import org.apache.http.params.CoreConnectionPNames; import org.apache.http.params.CoreProtocolPNames; import org.apache.http.params.HttpParams; import org.apache.http.protocol.BasicHttpProcessor; import org.apache.http.protocol.ExecutionContext; import org.apache.http.protocol.HttpContext; import org.apache.http.protocol.RequestConnControl; import org.apache.http.protocol.RequestContent; import org.apache.http.protocol.RequestExpectContinue; import org.apache.http.protocol.RequestTargetHost; import org.apache.http.protocol.RequestUserAgent; import org.apache.http.util.EntityUtils; import org.limewire.common.LimeWireCommonModule; import org.limewire.http.reactor.LimeConnectingIOReactor; import org.limewire.io.NetworkInstanceUtils; import org.limewire.io.SimpleNetworkInstanceUtils; import org.limewire.net.EmptyProxySettings; import org.limewire.net.EmptySocketBindingSettings; import org.limewire.net.LimeWireNetModule; import org.limewire.net.ProxySettings; import org.limewire.net.SocketBindingSettings; import org.limewire.net.SocketsManager; import org.limewire.nio.NIODispatcher; import org.limewire.util.BaseTestCase; import com.google.inject.AbstractModule; import com.google.inject.Guice; import com.google.inject.Injector; public class LimeConnectingIOReactorTest extends BaseTestCase { private SocketsManager socketsManager; public LimeConnectingIOReactorTest(String name) { super(name); } public static Test suite() { return buildTestSuite(LimeConnectingIOReactorTest.class); } public static void main(String args[]) { junit.textui.TestRunner.run(suite()); } @Override protected void setUp() throws Exception { Injector injector = Guice.createInjector(new LimeWireCommonModule(), new LimeWireNetModule(), new AbstractModule() { @Override protected void configure() { bind(ProxySettings.class).to(EmptyProxySettings.class); bind(SocketBindingSettings.class).to(EmptySocketBindingSettings.class); bind(NetworkInstanceUtils.class).to(SimpleNetworkInstanceUtils.class); } }); socketsManager = injector.getInstance(SocketsManager.class); } public void testConnect() throws Exception { HttpParams params = new BasicHttpParams(); params .setIntParameter(CoreConnectionPNames.SO_TIMEOUT, 5000) .setIntParameter(CoreConnectionPNames.CONNECTION_TIMEOUT, 10000) .setIntParameter(CoreConnectionPNames.SOCKET_BUFFER_SIZE, 8 * 1024) .setParameter(CoreProtocolPNames.USER_AGENT, "HttpComponents/1.1"); final ConnectingIOReactor ioReactor = new LimeConnectingIOReactor(params, NIODispatcher.instance().getScheduledExecutorService(), socketsManager); BasicHttpProcessor httpproc = new BasicHttpProcessor(); httpproc.addInterceptor(new RequestContent()); httpproc.addInterceptor(new RequestTargetHost()); httpproc.addInterceptor(new RequestConnControl()); httpproc.addInterceptor(new RequestUserAgent()); httpproc.addInterceptor(new RequestExpectContinue()); CountDownLatch requestCount = new CountDownLatch(3); AsyncNHttpClientHandler handler = new AsyncNHttpClientHandler( httpproc, new MyHttpRequestExecutionHandler(requestCount), new DefaultConnectionReuseStrategy(), params); final IOEventDispatch ioEventDispatch = new DefaultClientIOEventDispatch(handler, params); ioReactor.execute(ioEventDispatch); SessionRequest[] reqs = new SessionRequest[(int)requestCount.getCount()]; SessionRequestCallback[] callbacks = new SessionRequestCallback[reqs.length]; for(int i = 0; i < callbacks.length; i++) { callbacks[i] = new SessionRequestCallback() { public void cancelled(SessionRequest arg0) { fail("couldn't connect!"); } public void completed(SessionRequest arg0) { } public void failed(SessionRequest arg0) { fail("couldn't connect!"); } public void timeout(SessionRequest arg0) { fail("couldn't connect!"); } }; } reqs[0] = ioReactor.connect( new InetSocketAddress("www.yahoo.com", 80), null, new HttpHost("www.yahoo.com"), callbacks[0]); reqs[1] = ioReactor.connect( new InetSocketAddress("www.google.com", 80), null, new HttpHost("www.google.com"), callbacks[1]); reqs[2] = ioReactor.connect( new InetSocketAddress("www.apache.org", 80), null, new HttpHost("www.apache.org"), callbacks[2]); assertTrue(requestCount.await(15, TimeUnit.SECONDS)); for(SessionRequest req : reqs) { assertTrue(req.isCompleted()); assertNull(req.getException()); } } public void testDoesntConnect() throws Exception { HttpParams params = new BasicHttpParams(); params .setIntParameter(CoreConnectionPNames.SO_TIMEOUT, 5000) .setIntParameter(CoreConnectionPNames.CONNECTION_TIMEOUT, 10000) .setIntParameter(CoreConnectionPNames.SOCKET_BUFFER_SIZE, 8 * 1024) .setParameter(CoreProtocolPNames.USER_AGENT, "HttpComponents/1.1"); final ConnectingIOReactor ioReactor = new LimeConnectingIOReactor(params, NIODispatcher.instance().getScheduledExecutorService(), socketsManager); final CountDownLatch requestCount = new CountDownLatch(3); AsyncNHttpClientHandler handler = new AsyncNHttpClientHandler( new BasicHttpProcessor(), new FailingHandler(), new DefaultConnectionReuseStrategy(), params); final IOEventDispatch ioEventDispatch = new DefaultClientIOEventDispatch(handler, params); ioReactor.execute(ioEventDispatch); SessionRequest[] reqs = new SessionRequest[(int)requestCount.getCount()]; SessionRequestCallback[] callbacks = new SessionRequestCallback[reqs.length]; for(int i = 0; i < callbacks.length; i++) { callbacks[i] = new SessionRequestCallback() { public void cancelled(SessionRequest arg0) { fail("wrong method"); } public void completed(SessionRequest arg0) { fail("wrong method"); } public void failed(SessionRequest arg0) { requestCount.countDown(); } public void timeout(SessionRequest arg0) { fail("wrong method"); } }; } reqs[0] = ioReactor.connect( new InetSocketAddress("asdfoihasdfoihasdfoihadsf.2395", 80), null, null, callbacks[0]); reqs[1] = ioReactor.connect( new InetSocketAddress("asdfoihasdfoihasdfoihadsf.com", 80), null, null, callbacks[1]); reqs[2] = ioReactor.connect( new InetSocketAddress("asdfoihasdfoihasdfoihadsf.au", 80), null, null, callbacks[2]); assertTrue(requestCount.await(15, TimeUnit.SECONDS)); for(SessionRequest req : reqs) { assertTrue(req.isCompleted()); assertNotNull(req.getException()); } } static class FailingHandler implements NHttpRequestExecutionHandler { public void finalizeContext(HttpContext arg0) { fail("shouldn't be here!"); } public void handleResponse(HttpResponse arg0, HttpContext arg1) throws IOException { fail("shouldn't be here!"); } public void initalizeContext(HttpContext arg0, Object arg1) { fail("shouldn't be here!"); } public ConsumingNHttpEntity responseEntity(HttpResponse arg0, HttpContext arg1) throws IOException { fail("shouldn't be here!"); return null; } public HttpRequest submitRequest(HttpContext arg0) { fail("shouldn't be here!"); return null; } } static class MyHttpRequestExecutionHandler implements NHttpRequestExecutionHandler { private final static String REQUEST_SENT = "request-sent"; private final static String RESPONSE_RECEIVED = "response-received"; private final CountDownLatch requestCount; public MyHttpRequestExecutionHandler(final CountDownLatch requestCount) { super(); this.requestCount = requestCount; } public void initalizeContext(final HttpContext context, final Object attachment) { HttpHost targetHost = (HttpHost) attachment; context.setAttribute(ExecutionContext.HTTP_TARGET_HOST, targetHost); } public void finalizeContext(final HttpContext context) { Object flag = context.getAttribute(RESPONSE_RECEIVED); if (flag == null) { fail("didn't get a response from host: " + context.getAttribute(ExecutionContext.HTTP_TARGET_HOST)); } } public HttpRequest submitRequest(final HttpContext context) { Object flag = context.getAttribute(REQUEST_SENT); if (flag == null) { // Stick some object into the context context.setAttribute(REQUEST_SENT, Boolean.TRUE); return new BasicHttpRequest("GET", "/"); } else { // close the connections immediately try { ((NHttpConnection)context.getAttribute(ExecutionContext.HTTP_CONNECTION)).close(); } catch(IOException ignored) {} return null; } } public ConsumingNHttpEntity responseEntity(HttpResponse response, HttpContext context) throws IOException { return new BufferingNHttpEntity(response.getEntity(), new HeapByteBufferAllocator()); } public void handleResponse(final HttpResponse response, final HttpContext context) { HttpEntity entity = response.getEntity(); try { String content = EntityUtils.toString(entity); assertGreaterThan("failed requesting host: " + context.getAttribute(ExecutionContext.HTTP_TARGET_HOST), 1, content.length()); } catch (IOException ex) { fail(ex); } context.setAttribute(RESPONSE_RECEIVED, Boolean.TRUE); requestCount.countDown(); } } }