You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@hc.apache.org by ol...@apache.org on 2011/09/14 17:39:58 UTC

svn commit: r1170692 - in /httpcomponents/httpcore/trunk/httpcore-nio/src: main/java/org/apache/http/nio/protocol/HttpAsyncClientProtocolHandler.java test/java/org/apache/http/nio/protocol/TestHttpAsyncClientProtocolHandler.java

Author: olegk
Date: Wed Sep 14 15:39:58 2011
New Revision: 1170692

URL: http://svn.apache.org/viewvc?rev=1170692&view=rev
Log:
Unit tests for HttpAsyncClientProtocolHandler

Added:
    httpcomponents/httpcore/trunk/httpcore-nio/src/test/java/org/apache/http/nio/protocol/TestHttpAsyncClientProtocolHandler.java   (with props)
Modified:
    httpcomponents/httpcore/trunk/httpcore-nio/src/main/java/org/apache/http/nio/protocol/HttpAsyncClientProtocolHandler.java

Modified: httpcomponents/httpcore/trunk/httpcore-nio/src/main/java/org/apache/http/nio/protocol/HttpAsyncClientProtocolHandler.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpcore/trunk/httpcore-nio/src/main/java/org/apache/http/nio/protocol/HttpAsyncClientProtocolHandler.java?rev=1170692&r1=1170691&r2=1170692&view=diff
==============================================================================
--- httpcomponents/httpcore/trunk/httpcore-nio/src/main/java/org/apache/http/nio/protocol/HttpAsyncClientProtocolHandler.java (original)
+++ httpcomponents/httpcore/trunk/httpcore-nio/src/main/java/org/apache/http/nio/protocol/HttpAsyncClientProtocolHandler.java Wed Sep 14 15:39:58 2011
@@ -53,7 +53,6 @@ import org.apache.http.protocol.HttpCont
 public class HttpAsyncClientProtocolHandler implements NHttpClientHandler {
 
     public static final String HTTP_HANDLER = "http.nio.exchange-handler";
-    private static final String HTTP_EXCHNAGE = "http.nio.exchange";
 
     public HttpAsyncClientProtocolHandler() {
         super();
@@ -74,7 +73,7 @@ public class HttpAsyncClientProtocolHand
     }
 
     public void exception(final NHttpClientConnection conn, final HttpException ex) {
-        HttpExchange httpexchange = getHttpExchange(conn);
+        HttpExchange httpexchange = ensureNotNull(getHttpExchange(conn));
         HttpAsyncClientExchangeHandler<?> handler = httpexchange.getHandler();
         if (handler != null) {
             handler.failed(ex);
@@ -83,7 +82,7 @@ public class HttpAsyncClientProtocolHand
     }
 
     public void exception(final NHttpClientConnection conn, final IOException ex) {
-        HttpExchange httpexchange = getHttpExchange(conn);
+        HttpExchange httpexchange = ensureNotNull(getHttpExchange(conn));
         HttpAsyncClientExchangeHandler<?> handler = httpexchange.getHandler();
         if (handler != null) {
             handler.failed(ex);
@@ -92,7 +91,7 @@ public class HttpAsyncClientProtocolHand
     }
 
     public void requestReady(final NHttpClientConnection conn) {
-        HttpExchange httpexchange = getHttpExchange(conn);
+        HttpExchange httpexchange = ensureNotNull(getHttpExchange(conn));
         if (httpexchange.getRequestState() != MessageState.READY) {
             return;
         }
@@ -114,15 +113,10 @@ public class HttpAsyncClientProtocolHand
             HttpRequest request = handler.generateRequest();
             httpexchange.setRequest(request);
 
-            HttpEntityEnclosingRequest entityReq = null;
-            if (request instanceof HttpEntityEnclosingRequest) {
-                entityReq = (HttpEntityEnclosingRequest) request;
-            }
-
             conn.submitRequest(request);
 
-            if (entityReq != null) {
-                if (entityReq.expectContinue()) {
+            if (request instanceof HttpEntityEnclosingRequest) {
+                if (((HttpEntityEnclosingRequest) request).expectContinue()) {
                     int timeout = conn.getSocketTimeout();
                     httpexchange.setTimeout(timeout);
                     timeout = request.getParams().getIntParameter(
@@ -147,28 +141,9 @@ public class HttpAsyncClientProtocolHand
         }
     }
 
-    public void inputReady(final NHttpClientConnection conn, final ContentDecoder decoder) {
-        HttpExchange httpexchange = getHttpExchange(conn);
-        HttpAsyncClientExchangeHandler<?> handler = httpexchange.getHandler();
-        try {
-            handler.consumeContent(decoder, conn);
-            if (decoder.isCompleted()) {
-                processResponse(conn, httpexchange, handler);
-            }
-        } catch (RuntimeException ex) {
-            shutdownConnection(conn);
-            handler.failed(ex);
-            throw ex;
-        } catch (Exception ex) {
-            shutdownConnection(conn);
-            handler.failed(ex);
-            onException(ex);
-        }
-    }
-
     public void outputReady(final NHttpClientConnection conn, final ContentEncoder encoder) {
-        HttpExchange httpexchange = getHttpExchange(conn);
-        HttpAsyncClientExchangeHandler<?> handler = httpexchange.getHandler();
+        HttpExchange httpexchange = ensureNotNull(getHttpExchange(conn));
+        HttpAsyncClientExchangeHandler<?> handler = ensureNotNull(httpexchange.getHandler());
         try {
             if (httpexchange.getRequestState() == MessageState.ACK_EXPECTED) {
                 conn.suspendOutput();
@@ -176,6 +151,7 @@ public class HttpAsyncClientProtocolHand
             }
             HttpContext context = handler.getContext();
             handler.produceContent(encoder, conn);
+            httpexchange.setRequestState(MessageState.BODY_STREAM);
             if (encoder.isCompleted()) {
                 handler.requestCompleted(context);
                 httpexchange.setRequestState(MessageState.COMPLETED);
@@ -192,8 +168,8 @@ public class HttpAsyncClientProtocolHand
     }
 
     public void responseReceived(final NHttpClientConnection conn) {
-        HttpExchange httpexchange = getHttpExchange(conn);
-        HttpAsyncClientExchangeHandler<?> handler = httpexchange.getHandler();
+        HttpExchange httpexchange = ensureNotNull(getHttpExchange(conn));
+        HttpAsyncClientExchangeHandler<?> handler = ensureNotNull(httpexchange.getHandler());
         try {
             HttpResponse response = conn.getHttpResponse();
             HttpRequest request = httpexchange.getRequest();
@@ -209,26 +185,25 @@ public class HttpAsyncClientProtocolHand
                     int timeout = httpexchange.getTimeout();
                     conn.setSocketTimeout(timeout);
                     conn.requestOutput();
-                    httpexchange.setRequestState(MessageState.BODY_STREAM);
+                    httpexchange.setRequestState(MessageState.ACK);
                 }
                 return;
-            } else {
-                httpexchange.setResponse(response);
-                if (httpexchange.getRequestState() == MessageState.ACK_EXPECTED) {
-                    int timeout = httpexchange.getTimeout();
-                    conn.setSocketTimeout(timeout);
-                    conn.resetOutput();
-                    httpexchange.setRequestState(MessageState.COMPLETED);
-                } else if (httpexchange.getRequestState() == MessageState.BODY_STREAM) {
-                    // Early response
-                    int timeout = httpexchange.getTimeout();
-                    conn.setSocketTimeout(timeout);
-                    conn.suspendOutput();
-                    conn.resetOutput();
-                    httpexchange.invalidate();
-                }
+            }
+            httpexchange.setResponse(response);
+            if (httpexchange.getRequestState() == MessageState.ACK_EXPECTED) {
+                int timeout = httpexchange.getTimeout();
+                conn.setSocketTimeout(timeout);
+                conn.resetOutput();
+                httpexchange.setRequestState(MessageState.COMPLETED);
+            } else if (httpexchange.getRequestState() == MessageState.BODY_STREAM) {
+                // Early response
+                conn.resetOutput();
+                conn.suspendOutput();
+                httpexchange.setRequestState(MessageState.COMPLETED);
+                httpexchange.invalidate();
             }
             handler.responseReceived(response);
+            httpexchange.setResponseState(MessageState.BODY_STREAM);
             if (!canResponseHaveBody(request, response)) {
                 conn.resetInput();
                 processResponse(conn, httpexchange, handler);
@@ -244,8 +219,28 @@ public class HttpAsyncClientProtocolHand
         }
     }
 
+    public void inputReady(final NHttpClientConnection conn, final ContentDecoder decoder) {
+        HttpExchange httpexchange = ensureNotNull(getHttpExchange(conn));
+        HttpAsyncClientExchangeHandler<?> handler = ensureNotNull(httpexchange.getHandler());
+        try {
+            handler.consumeContent(decoder, conn);
+            httpexchange.setResponseState(MessageState.BODY_STREAM);
+            if (decoder.isCompleted()) {
+                processResponse(conn, httpexchange, handler);
+            }
+        } catch (RuntimeException ex) {
+            shutdownConnection(conn);
+            handler.failed(ex);
+            throw ex;
+        } catch (Exception ex) {
+            shutdownConnection(conn);
+            handler.failed(ex);
+            onException(ex);
+        }
+    }
+
     public void timeout(final NHttpClientConnection conn) {
-        HttpExchange httpexchange = getHttpExchange(conn);
+        HttpExchange httpexchange = ensureNotNull(getHttpExchange(conn));
         HttpAsyncClientExchangeHandler<?> handler = httpexchange.getHandler();
         if (handler == null) {
             shutdownConnection(conn);
@@ -260,24 +255,20 @@ public class HttpAsyncClientProtocolHand
             } else {
                 handler.failed(new SocketTimeoutException());
                 if (conn.getStatus() == NHttpConnection.ACTIVE) {
-                    conn.close();
+                    closeConnection(conn);
                     if (conn.getStatus() == NHttpConnection.CLOSING) {
                         // Give the connection some grace time to
                         // close itself nicely
                         conn.setSocketTimeout(250);
                     }
                 } else {
-                    conn.shutdown();
+                    shutdownConnection(conn);
                 }
             }
         } catch (RuntimeException ex) {
             shutdownConnection(conn);
             handler.failed(ex);
             throw ex;
-        } catch (Exception ex) {
-            shutdownConnection(conn);
-            handler.failed(ex);
-            onException(ex);
         }
     }
 
@@ -288,11 +279,7 @@ public class HttpAsyncClientProtocolHand
         try {
             conn.close();
         } catch (IOException ex) {
-            try {
-                conn.shutdown();
-            } catch (IOException ex2) {
-                onException(ex2);
-            }
+            onException(ex);
         }
     }
 
@@ -308,26 +295,38 @@ public class HttpAsyncClientProtocolHand
         return (HttpExchange) conn.getContext().getAttribute(HTTP_EXCHNAGE);
     }
 
+    private HttpExchange ensureNotNull(final HttpExchange httpExchange) {
+        if (httpExchange == null) {
+            throw new IllegalStateException("HTTP exchange is null");
+        }
+        return httpExchange;
+    }
+
+    private HttpAsyncClientExchangeHandler<?> ensureNotNull(final HttpAsyncClientExchangeHandler<?> handler) {
+        if (handler == null) {
+            throw new IllegalStateException("HTTP exchange handler is null");
+        }
+        return handler;
+    }
+
     private void processResponse(
             final NHttpClientConnection conn,
             final HttpExchange httpexchange,
             final HttpAsyncClientExchangeHandler<?> handler) throws IOException {
-        if (!httpexchange.isValid()) {
-            conn.close();
-        }
         HttpContext context = handler.getContext();
-        HttpRequest request = httpexchange.getRequest();
-        HttpResponse response = httpexchange.getResponse();
-
-        String method = request.getRequestLine().getMethod();
-        int status = response.getStatusLine().getStatusCode();
-        if (method.equalsIgnoreCase("CONNECT") && status == HttpStatus.SC_OK) {
-            conn.resetInput();
-        } else {
-            ConnectionReuseStrategy connReuseStrategy = handler.getConnectionReuseStrategy();
-            if (!connReuseStrategy.keepAlive(response, context)) {
-                conn.close();
+        if (httpexchange.isValid()) {
+            HttpRequest request = httpexchange.getRequest();
+            HttpResponse response = httpexchange.getResponse();
+            String method = request.getRequestLine().getMethod();
+            int status = response.getStatusLine().getStatusCode();
+            if (!(method.equalsIgnoreCase("CONNECT") && status < 300)) {
+                ConnectionReuseStrategy connReuseStrategy = handler.getConnectionReuseStrategy();
+                if (!connReuseStrategy.keepAlive(response, context)) {
+                    conn.close();
+                }
             }
+        } else {
+            conn.close();
         }
         handler.responseCompleted(context);
         httpexchange.reset();
@@ -341,7 +340,7 @@ public class HttpAsyncClientProtocolHand
         if (method.equalsIgnoreCase("HEAD")) {
             return false;
         }
-        if (method.equalsIgnoreCase("CONNECT") && status == HttpStatus.SC_OK) {
+        if (method.equalsIgnoreCase("CONNECT") && status < 300) {
             return false;
         }
         return status >= HttpStatus.SC_OK
@@ -350,6 +349,8 @@ public class HttpAsyncClientProtocolHand
             && status != HttpStatus.SC_RESET_CONTENT;
     }
 
+    static final String HTTP_EXCHNAGE = "http.nio.exchange";
+
     class HttpExchange {
 
         private volatile HttpAsyncClientExchangeHandler<?> handler;

Added: httpcomponents/httpcore/trunk/httpcore-nio/src/test/java/org/apache/http/nio/protocol/TestHttpAsyncClientProtocolHandler.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpcore/trunk/httpcore-nio/src/test/java/org/apache/http/nio/protocol/TestHttpAsyncClientProtocolHandler.java?rev=1170692&view=auto
==============================================================================
--- httpcomponents/httpcore/trunk/httpcore-nio/src/test/java/org/apache/http/nio/protocol/TestHttpAsyncClientProtocolHandler.java (added)
+++ httpcomponents/httpcore/trunk/httpcore-nio/src/test/java/org/apache/http/nio/protocol/TestHttpAsyncClientProtocolHandler.java Wed Sep 14 15:39:58 2011
@@ -0,0 +1,765 @@
+/*
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation.  For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.nio.protocol;
+
+import java.io.IOException;
+import java.net.SocketTimeoutException;
+
+import junit.framework.Assert;
+
+import org.apache.http.ConnectionReuseStrategy;
+import org.apache.http.HttpException;
+import org.apache.http.HttpRequest;
+import org.apache.http.HttpStatus;
+import org.apache.http.HttpVersion;
+import org.apache.http.message.BasicHttpEntityEnclosingRequest;
+import org.apache.http.message.BasicHttpRequest;
+import org.apache.http.message.BasicHttpResponse;
+import org.apache.http.nio.ContentDecoder;
+import org.apache.http.nio.ContentEncoder;
+import org.apache.http.nio.NHttpClientConnection;
+import org.apache.http.nio.NHttpConnection;
+import org.apache.http.nio.entity.NStringEntity;
+import org.apache.http.nio.protocol.HttpAsyncClientProtocolHandler.HttpExchange;
+import org.apache.http.protocol.BasicHttpContext;
+import org.apache.http.protocol.HTTP;
+import org.apache.http.protocol.HttpContext;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mockito;
+
+public class TestHttpAsyncClientProtocolHandler {
+
+    private HttpAsyncClientProtocolHandler protocolHandler;
+    private HttpContext connContext;
+    private NHttpClientConnection conn;
+    private HttpAsyncClientExchangeHandler<?> exchangeHandler;
+    private HttpContext exchangeContext;
+    private ContentEncoder encoder;
+    private ContentDecoder decoder;
+    private ConnectionReuseStrategy reuseStrategy;
+
+    @Before
+    public void setUp() throws Exception {
+        this.protocolHandler = new HttpAsyncClientProtocolHandler();
+        this.connContext = new BasicHttpContext();
+        this.conn = Mockito.mock(NHttpClientConnection.class);
+        this.exchangeHandler = Mockito.mock(HttpAsyncClientExchangeHandler.class);
+        this.exchangeContext = new BasicHttpContext();
+        this.encoder = Mockito.mock(ContentEncoder.class);
+        this.decoder = Mockito.mock(ContentDecoder.class);
+        this.reuseStrategy = Mockito.mock(ConnectionReuseStrategy.class);
+
+        Mockito.when(this.conn.getContext()).thenReturn(this.connContext);
+        Mockito.when(this.exchangeHandler.getContext()).thenReturn(this.exchangeContext);
+    }
+
+    @After
+    public void tearDown() throws Exception {
+    }
+
+    @Test
+    public void testConnected() throws Exception {
+        HttpRequest request = new BasicHttpRequest("GET", "/");
+        Mockito.when(this.exchangeHandler.generateRequest()).thenReturn(request);
+        this.connContext.setAttribute(HttpAsyncClientProtocolHandler.HTTP_HANDLER, this.exchangeHandler);
+
+        this.protocolHandler.connected(this.conn, null);
+
+        HttpExchange httpExchange = (HttpExchange) this.connContext.getAttribute(
+                HttpAsyncClientProtocolHandler.HTTP_EXCHNAGE);
+        Assert.assertNotNull(httpExchange);
+        Assert.assertSame(this.exchangeHandler, httpExchange.getHandler());
+        Mockito.verify(this.exchangeHandler).generateRequest();
+        Assert.assertSame(request, httpExchange.getRequest());
+        Mockito.verify(this.conn).submitRequest(request);
+        Mockito.verify(this.exchangeHandler).requestCompleted(this.exchangeContext);
+        Assert.assertEquals(MessageState.COMPLETED, httpExchange.getRequestState());
+        Assert.assertEquals("request state: COMPLETED; request: GET / HTTP/1.1; " +
+                "response state: READY; response: ; valid: true;", httpExchange.toString());
+    }
+
+    @Test
+    public void testClosed() throws Exception {
+        HttpExchange httpExchange = this.protocolHandler.new HttpExchange();
+        httpExchange.setRequestState(MessageState.COMPLETED);
+        httpExchange.setResponseState(MessageState.COMPLETED);
+        httpExchange.setHandler(this.exchangeHandler);
+        this.connContext.setAttribute(HttpAsyncClientProtocolHandler.HTTP_EXCHNAGE, httpExchange);
+
+        this.protocolHandler.closed(this.conn);
+
+        Assert.assertNull(httpExchange.getHandler());
+        Assert.assertEquals(MessageState.READY, httpExchange.getRequestState());
+        Assert.assertEquals(MessageState.READY, httpExchange.getResponseState());
+        Mockito.verify(this.exchangeHandler).close();
+    }
+
+    @Test
+    public void testHttpException() throws Exception {
+        HttpExchange httpExchange = this.protocolHandler.new HttpExchange();
+        httpExchange.setRequestState(MessageState.COMPLETED);
+        httpExchange.setResponseState(MessageState.COMPLETED);
+        httpExchange.setHandler(this.exchangeHandler);
+        this.connContext.setAttribute(HttpAsyncClientProtocolHandler.HTTP_EXCHNAGE, httpExchange);
+
+        HttpException httpex = new HttpException();
+        this.protocolHandler.exception(this.conn, httpex);
+
+        Assert.assertNotNull(httpExchange.getHandler());
+        Mockito.verify(this.exchangeHandler).failed(httpex);
+        Mockito.verify(this.conn).close();
+    }
+
+    @Test
+    public void testIOException() throws Exception {
+        HttpExchange httpExchange = this.protocolHandler.new HttpExchange();
+        httpExchange.setRequestState(MessageState.COMPLETED);
+        httpExchange.setResponseState(MessageState.COMPLETED);
+        httpExchange.setHandler(this.exchangeHandler);
+        this.connContext.setAttribute(HttpAsyncClientProtocolHandler.HTTP_EXCHNAGE, httpExchange);
+
+        IOException ioex = new IOException();
+        this.protocolHandler.exception(this.conn, ioex);
+
+        Assert.assertNotNull(httpExchange.getHandler());
+        Mockito.verify(this.exchangeHandler).failed(ioex);
+        Mockito.verify(this.conn).shutdown();
+    }
+
+    @Test
+    public void testSimpleRequest() throws Exception {
+        HttpExchange httpExchange = this.protocolHandler.new HttpExchange();
+        httpExchange.setHandler(this.exchangeHandler);
+        this.connContext.setAttribute(HttpAsyncClientProtocolHandler.HTTP_EXCHNAGE, httpExchange);
+        HttpRequest request = new BasicHttpRequest("GET", "/");
+        Mockito.when(this.exchangeHandler.generateRequest()).thenReturn(request);
+
+        this.protocolHandler.requestReady(this.conn);
+
+        Mockito.verify(this.exchangeHandler).generateRequest();
+        Assert.assertSame(request, httpExchange.getRequest());
+        Mockito.verify(this.conn).submitRequest(request);
+        Mockito.verify(this.exchangeHandler).requestCompleted(this.exchangeContext);
+        Assert.assertEquals(MessageState.COMPLETED, httpExchange.getRequestState());
+    }
+
+    @Test
+    public void testEntityEnclosingRequestWithoutExpectContinue() throws Exception {
+        HttpExchange httpExchange = this.protocolHandler.new HttpExchange();
+        httpExchange.setHandler(this.exchangeHandler);
+        this.connContext.setAttribute(HttpAsyncClientProtocolHandler.HTTP_EXCHNAGE, httpExchange);
+        BasicHttpEntityEnclosingRequest request = new BasicHttpEntityEnclosingRequest("POST", "/");
+        request.setEntity(NStringEntity.create("stuff"));
+        Mockito.when(this.exchangeHandler.generateRequest()).thenReturn(request);
+
+        this.protocolHandler.requestReady(this.conn);
+
+        Mockito.verify(this.exchangeHandler).generateRequest();
+        Assert.assertSame(request, httpExchange.getRequest());
+        Mockito.verify(this.conn).submitRequest(request);
+        Mockito.verify(this.exchangeHandler, Mockito.never()).requestCompleted(this.exchangeContext);
+        Assert.assertEquals(MessageState.BODY_STREAM, httpExchange.getRequestState());
+    }
+
+    @Test
+    public void testEntityEnclosingRequestWithExpectContinue() throws Exception {
+        HttpExchange httpExchange = this.protocolHandler.new HttpExchange();
+        httpExchange.setHandler(this.exchangeHandler);
+        this.connContext.setAttribute(HttpAsyncClientProtocolHandler.HTTP_EXCHNAGE, httpExchange);
+        BasicHttpEntityEnclosingRequest request = new BasicHttpEntityEnclosingRequest("POST", "/");
+        request.setHeader(HTTP.EXPECT_DIRECTIVE, HTTP.EXPECT_CONTINUE);
+        Mockito.when(this.exchangeHandler.generateRequest()).thenReturn(request);
+        Mockito.when(this.conn.getSocketTimeout()).thenReturn(1000);
+
+        this.protocolHandler.requestReady(this.conn);
+
+        Mockito.verify(this.exchangeHandler).generateRequest();
+        Assert.assertSame(request, httpExchange.getRequest());
+        Mockito.verify(this.conn).submitRequest(request);
+        Mockito.verify(this.conn).setSocketTimeout(3000);
+        Assert.assertEquals(1000, httpExchange.getTimeout());
+        Mockito.verify(this.exchangeHandler, Mockito.never()).requestCompleted(this.exchangeContext);
+        Assert.assertEquals(MessageState.ACK_EXPECTED, httpExchange.getRequestState());
+    }
+
+    @Test
+    public void testRequestRuntimeException() throws Exception {
+        RuntimeException runtimeEx = new RuntimeException();
+        HttpExchange httpExchange = this.protocolHandler.new HttpExchange();
+        httpExchange.setHandler(this.exchangeHandler);
+        this.connContext.setAttribute(HttpAsyncClientProtocolHandler.HTTP_EXCHNAGE, httpExchange);
+        Mockito.when(this.exchangeHandler.generateRequest()).thenThrow(runtimeEx);
+        try {
+            this.protocolHandler.requestReady(this.conn);
+            Assert.fail("RuntimeException expected");
+        } catch (RuntimeException ex) {
+            Mockito.verify(this.conn).shutdown();
+            Mockito.verify(this.exchangeHandler).failed(ex);
+        }
+    }
+
+    @Test
+    public void testRequestHttpException() throws Exception {
+        HttpException httpex = new HttpException();
+        HttpExchange httpExchange = this.protocolHandler.new HttpExchange();
+        httpExchange.setHandler(this.exchangeHandler);
+        this.connContext.setAttribute(HttpAsyncClientProtocolHandler.HTTP_EXCHNAGE, httpExchange);
+        Mockito.when(this.exchangeHandler.generateRequest()).thenThrow(httpex);
+
+        this.protocolHandler.requestReady(this.conn);
+
+        Mockito.verify(this.conn).shutdown();
+        Mockito.verify(this.exchangeHandler).failed(httpex);
+    }
+
+    @Test
+    public void testRequestContentOutput() throws Exception {
+        HttpExchange httpExchange = this.protocolHandler.new HttpExchange();
+        httpExchange.setHandler(this.exchangeHandler);
+        this.connContext.setAttribute(HttpAsyncClientProtocolHandler.HTTP_EXCHNAGE, httpExchange);
+        Mockito.when(this.encoder.isCompleted()).thenReturn(false);
+
+        this.protocolHandler.outputReady(this.conn, this.encoder);
+
+        Mockito.verify(this.exchangeHandler).produceContent(this.encoder, this.conn);
+        Assert.assertEquals(MessageState.BODY_STREAM, httpExchange.getRequestState());
+    }
+
+    @Test
+    public void testRequestContentOutputCompleted() throws Exception {
+        HttpExchange httpExchange = this.protocolHandler.new HttpExchange();
+        httpExchange.setHandler(this.exchangeHandler);
+        this.connContext.setAttribute(HttpAsyncClientProtocolHandler.HTTP_EXCHNAGE, httpExchange);
+        Mockito.when(this.encoder.isCompleted()).thenReturn(true);
+
+        this.protocolHandler.outputReady(this.conn, this.encoder);
+
+        Mockito.verify(this.exchangeHandler).produceContent(this.encoder, this.conn);
+        Mockito.verify(this.exchangeHandler).requestCompleted(this.exchangeContext);
+        Assert.assertEquals(MessageState.COMPLETED, httpExchange.getRequestState());
+    }
+
+    @Test
+    public void testRequestContentContinueExpected() throws Exception {
+        HttpExchange httpExchange = this.protocolHandler.new HttpExchange();
+        httpExchange.setRequestState(MessageState.ACK_EXPECTED);
+        httpExchange.setHandler(this.exchangeHandler);
+        this.connContext.setAttribute(HttpAsyncClientProtocolHandler.HTTP_EXCHNAGE, httpExchange);
+
+        this.protocolHandler.outputReady(this.conn, this.encoder);
+
+        Mockito.verify(this.conn).suspendOutput();
+        Mockito.verify(this.exchangeHandler, Mockito.never()).produceContent(this.encoder, this.conn);
+        Assert.assertEquals(MessageState.ACK_EXPECTED, httpExchange.getRequestState());
+    }
+
+    @Test
+    public void testRequestContentRuntimeException() throws Exception {
+        RuntimeException runtimeEx = new RuntimeException();
+        HttpExchange httpExchange = this.protocolHandler.new HttpExchange();
+        httpExchange.setHandler(this.exchangeHandler);
+        this.connContext.setAttribute(HttpAsyncClientProtocolHandler.HTTP_EXCHNAGE, httpExchange);
+        Mockito.doThrow(runtimeEx).when(this.exchangeHandler).produceContent(this.encoder, this.conn);
+
+        try {
+            this.protocolHandler.outputReady(this.conn, this.encoder);
+            Assert.fail("RuntimeException expected");
+        } catch (RuntimeException ex) {
+            Mockito.verify(this.conn).shutdown();
+            Mockito.verify(this.exchangeHandler).failed(ex);
+        }
+    }
+
+    @Test
+    public void testRequestContentIOException() throws Exception {
+        IOException ioex = new IOException();
+        HttpExchange httpExchange = this.protocolHandler.new HttpExchange();
+        httpExchange.setHandler(this.exchangeHandler);
+        this.connContext.setAttribute(HttpAsyncClientProtocolHandler.HTTP_EXCHNAGE, httpExchange);
+        Mockito.doThrow(ioex).when(this.exchangeHandler).produceContent(this.encoder, this.conn);
+
+        this.protocolHandler.outputReady(this.conn, this.encoder);
+
+        Mockito.verify(this.conn).shutdown();
+        Mockito.verify(this.exchangeHandler).failed(ioex);
+    }
+
+    @Test
+    public void testNormalResponse() throws Exception {
+        HttpExchange httpExchange = this.protocolHandler.new HttpExchange();
+        HttpRequest request = new BasicHttpRequest("GET", "/");
+        httpExchange.setRequest(request);
+        httpExchange.setHandler(this.exchangeHandler);
+        this.connContext.setAttribute(HttpAsyncClientProtocolHandler.HTTP_EXCHNAGE, httpExchange);
+        BasicHttpResponse response = new BasicHttpResponse(HttpVersion.HTTP_1_1, 200, "OK");
+        Mockito.when(this.conn.getHttpResponse()).thenReturn(response);
+
+        this.protocolHandler.responseReceived(this.conn);
+
+        Assert.assertSame(response, httpExchange.getResponse());
+        Assert.assertEquals(MessageState.BODY_STREAM, httpExchange.getResponseState());
+    }
+
+    @Test
+    public void testResponse100() throws Exception {
+        HttpExchange httpExchange = this.protocolHandler.new HttpExchange();
+        httpExchange.setRequestState(MessageState.ACK_EXPECTED);
+        httpExchange.setTimeout(1000);
+        BasicHttpEntityEnclosingRequest request = new BasicHttpEntityEnclosingRequest("POST", "/");
+        request.setEntity(NStringEntity.create("stuff"));
+        httpExchange.setRequest(request);
+        httpExchange.setHandler(this.exchangeHandler);
+        this.connContext.setAttribute(HttpAsyncClientProtocolHandler.HTTP_EXCHNAGE, httpExchange);
+        BasicHttpResponse response = new BasicHttpResponse(HttpVersion.HTTP_1_1, 100, "Continue");
+        Mockito.when(this.conn.getHttpResponse()).thenReturn(response);
+
+        this.protocolHandler.responseReceived(this.conn);
+
+        Assert.assertNull(httpExchange.getResponse());
+        Assert.assertEquals(MessageState.ACK, httpExchange.getRequestState());
+        Assert.assertEquals(MessageState.READY, httpExchange.getResponseState());
+        Mockito.verify(this.conn).setSocketTimeout(1000);
+        Mockito.verify(this.conn).requestOutput();
+    }
+
+    @Test
+    public void testResponse100OutOfSequence() throws Exception {
+        HttpExchange httpExchange = this.protocolHandler.new HttpExchange();
+        httpExchange.setRequestState(MessageState.COMPLETED);
+        BasicHttpEntityEnclosingRequest request = new BasicHttpEntityEnclosingRequest("POST", "/");
+        request.setEntity(NStringEntity.create("stuff"));
+        httpExchange.setRequest(request);
+        httpExchange.setHandler(this.exchangeHandler);
+        this.connContext.setAttribute(HttpAsyncClientProtocolHandler.HTTP_EXCHNAGE, httpExchange);
+        BasicHttpResponse response = new BasicHttpResponse(HttpVersion.HTTP_1_1, 100, "Continue");
+        Mockito.when(this.conn.getHttpResponse()).thenReturn(response);
+
+        this.protocolHandler.responseReceived(this.conn);
+
+        Assert.assertNull(httpExchange.getResponse());
+        Assert.assertEquals(MessageState.COMPLETED, httpExchange.getRequestState());
+        Mockito.verify(this.conn, Mockito.never()).requestOutput();
+    }
+
+    @Test
+    public void testResponse111() throws Exception {
+        HttpExchange httpExchange = this.protocolHandler.new HttpExchange();
+        httpExchange.setRequestState(MessageState.ACK_EXPECTED);
+        httpExchange.setTimeout(1000);
+        BasicHttpEntityEnclosingRequest request = new BasicHttpEntityEnclosingRequest("POST", "/");
+        request.setEntity(NStringEntity.create("stuff"));
+        httpExchange.setRequest(request);
+        httpExchange.setHandler(this.exchangeHandler);
+        this.connContext.setAttribute(HttpAsyncClientProtocolHandler.HTTP_EXCHNAGE, httpExchange);
+        BasicHttpResponse response = new BasicHttpResponse(HttpVersion.HTTP_1_1, 111, "WTF?");
+        Mockito.when(this.conn.getHttpResponse()).thenReturn(response);
+
+        this.protocolHandler.responseReceived(this.conn);
+
+        Assert.assertNull(httpExchange.getResponse());
+        Assert.assertEquals(MessageState.ACK_EXPECTED, httpExchange.getRequestState());
+        Mockito.verify(this.conn).shutdown();
+        Mockito.verify(this.exchangeHandler).failed(Mockito.any(HttpException.class));
+    }
+
+    @Test
+    public void testResponseExpectationFailed() throws Exception {
+        HttpExchange httpExchange = this.protocolHandler.new HttpExchange();
+        httpExchange.setRequestState(MessageState.ACK_EXPECTED);
+        httpExchange.setTimeout(1000);
+        BasicHttpEntityEnclosingRequest request = new BasicHttpEntityEnclosingRequest("POST", "/");
+        request.setEntity(NStringEntity.create("stuff"));
+        httpExchange.setRequest(request);
+        httpExchange.setHandler(this.exchangeHandler);
+        this.connContext.setAttribute(HttpAsyncClientProtocolHandler.HTTP_EXCHNAGE, httpExchange);
+        BasicHttpResponse response = new BasicHttpResponse(HttpVersion.HTTP_1_1, 403, "Unauthorized");
+        Mockito.when(this.conn.getHttpResponse()).thenReturn(response);
+
+        this.protocolHandler.responseReceived(this.conn);
+
+        Assert.assertSame(response, httpExchange.getResponse());
+        Assert.assertEquals(MessageState.COMPLETED, httpExchange.getRequestState());
+        Assert.assertEquals(MessageState.BODY_STREAM, httpExchange.getResponseState());
+        Mockito.verify(this.conn).setSocketTimeout(1000);
+        Mockito.verify(this.conn).resetOutput();
+    }
+
+    @Test
+    public void testEarlyResponse() throws Exception {
+        HttpExchange httpExchange = this.protocolHandler.new HttpExchange();
+        httpExchange.setRequestState(MessageState.BODY_STREAM);
+        httpExchange.setTimeout(1000);
+        BasicHttpEntityEnclosingRequest request = new BasicHttpEntityEnclosingRequest("POST", "/");
+        request.setEntity(NStringEntity.create("stuff"));
+        httpExchange.setRequest(request);
+        httpExchange.setHandler(this.exchangeHandler);
+        this.connContext.setAttribute(HttpAsyncClientProtocolHandler.HTTP_EXCHNAGE, httpExchange);
+        BasicHttpResponse response = new BasicHttpResponse(HttpVersion.HTTP_1_1, 403, "Unauthorized");
+        Mockito.when(this.conn.getHttpResponse()).thenReturn(response);
+
+        this.protocolHandler.responseReceived(this.conn);
+
+        Assert.assertSame(response, httpExchange.getResponse());
+        Assert.assertEquals(MessageState.COMPLETED, httpExchange.getRequestState());
+        Assert.assertEquals(MessageState.BODY_STREAM, httpExchange.getResponseState());
+        Mockito.verify(this.conn).suspendOutput();
+        Mockito.verify(this.conn).resetOutput();
+        Assert.assertFalse(httpExchange.isValid());
+    }
+
+    @Test
+    public void testResponseToHead() throws Exception {
+        HttpExchange httpExchange = this.protocolHandler.new HttpExchange();
+        HttpRequest request = new BasicHttpRequest("HEAD", "/");
+        httpExchange.setRequest(request);
+        httpExchange.setHandler(this.exchangeHandler);
+        this.connContext.setAttribute(HttpAsyncClientProtocolHandler.HTTP_EXCHNAGE, httpExchange);
+        BasicHttpResponse response = new BasicHttpResponse(HttpVersion.HTTP_1_1, 200, "OK");
+        Mockito.when(this.conn.getHttpResponse()).thenReturn(response);
+        Mockito.when(this.reuseStrategy.keepAlive(response, this.exchangeContext)).thenReturn(true);
+        Mockito.when(this.exchangeHandler.getConnectionReuseStrategy()).thenReturn(this.reuseStrategy);
+
+        this.protocolHandler.responseReceived(this.conn);
+
+        Assert.assertEquals(MessageState.READY, httpExchange.getResponseState());
+        Assert.assertEquals(MessageState.READY, httpExchange.getRequestState());
+        Assert.assertNull(httpExchange.getRequest());
+        Assert.assertNull(httpExchange.getResponse());
+        Mockito.verify(this.exchangeHandler).responseReceived(response);
+        Mockito.verify(this.conn).resetInput();
+        Mockito.verify(this.conn, Mockito.never()).close();
+    }
+
+    @Test
+    public void testResponseToConnect() throws Exception {
+        HttpExchange httpExchange = this.protocolHandler.new HttpExchange();
+        HttpRequest request = new BasicHttpRequest("Connect", "/");
+        httpExchange.setRequest(request);
+        httpExchange.setHandler(this.exchangeHandler);
+        this.connContext.setAttribute(HttpAsyncClientProtocolHandler.HTTP_EXCHNAGE, httpExchange);
+        BasicHttpResponse response = new BasicHttpResponse(HttpVersion.HTTP_1_1, 200, "OK");
+        Mockito.when(this.conn.getHttpResponse()).thenReturn(response);
+        Mockito.when(this.reuseStrategy.keepAlive(response, this.exchangeContext)).thenReturn(true);
+        Mockito.when(this.exchangeHandler.getConnectionReuseStrategy()).thenReturn(this.reuseStrategy);
+
+        this.protocolHandler.responseReceived(this.conn);
+
+        Assert.assertEquals(MessageState.READY, httpExchange.getResponseState());
+        Assert.assertEquals(MessageState.READY, httpExchange.getRequestState());
+        Assert.assertNull(httpExchange.getRequest());
+        Assert.assertNull(httpExchange.getResponse());
+        Mockito.verify(this.exchangeHandler).responseReceived(response);
+        Mockito.verify(this.conn).resetInput();
+        Mockito.verify(this.conn, Mockito.never()).close();
+    }
+
+    @Test
+    public void testResponseNotModified() throws Exception {
+        HttpExchange httpExchange = this.protocolHandler.new HttpExchange();
+        HttpRequest request = new BasicHttpRequest("Connect", "/");
+        httpExchange.setRequest(request);
+        httpExchange.setHandler(this.exchangeHandler);
+        this.connContext.setAttribute(HttpAsyncClientProtocolHandler.HTTP_EXCHNAGE, httpExchange);
+        BasicHttpResponse response = new BasicHttpResponse(HttpVersion.HTTP_1_1,
+                HttpStatus.SC_NOT_MODIFIED, "Not modified");
+        Mockito.when(this.conn.getHttpResponse()).thenReturn(response);
+        Mockito.when(this.reuseStrategy.keepAlive(response, this.exchangeContext)).thenReturn(true);
+        Mockito.when(this.exchangeHandler.getConnectionReuseStrategy()).thenReturn(this.reuseStrategy);
+
+        this.protocolHandler.responseReceived(this.conn);
+
+        Assert.assertEquals(MessageState.READY, httpExchange.getResponseState());
+        Assert.assertEquals(MessageState.READY, httpExchange.getRequestState());
+        Assert.assertNull(httpExchange.getRequest());
+        Assert.assertNull(httpExchange.getResponse());
+        Mockito.verify(this.exchangeHandler).responseReceived(response);
+        Mockito.verify(this.conn).resetInput();
+        Mockito.verify(this.conn, Mockito.never()).close();
+    }
+
+    @Test
+    public void testResponseRuntimeException() throws Exception {
+        RuntimeException runtimeEx = new RuntimeException();
+        HttpExchange httpExchange = this.protocolHandler.new HttpExchange();
+        HttpRequest request = new BasicHttpRequest("GET", "/");
+        httpExchange.setRequest(request);
+        httpExchange.setHandler(this.exchangeHandler);
+        this.connContext.setAttribute(HttpAsyncClientProtocolHandler.HTTP_EXCHNAGE, httpExchange);
+        BasicHttpResponse response = new BasicHttpResponse(HttpVersion.HTTP_1_1, 200, "OK");
+        Mockito.when(this.conn.getHttpResponse()).thenReturn(response);
+        Mockito.doThrow(runtimeEx).when(this.exchangeHandler).responseReceived(response);
+        try {
+            this.protocolHandler.responseReceived(this.conn);
+            Assert.fail("RuntimeException expected");
+        } catch (RuntimeException ex) {
+            Mockito.verify(this.conn).shutdown();
+            Mockito.verify(this.exchangeHandler).failed(ex);
+        }
+    }
+
+    @Test
+    public void testResponseHttpException() throws Exception {
+        HttpException httpex = new HttpException();
+        HttpExchange httpExchange = this.protocolHandler.new HttpExchange();
+        HttpRequest request = new BasicHttpRequest("GET", "/");
+        httpExchange.setRequest(request);
+        httpExchange.setHandler(this.exchangeHandler);
+        this.connContext.setAttribute(HttpAsyncClientProtocolHandler.HTTP_EXCHNAGE, httpExchange);
+        BasicHttpResponse response = new BasicHttpResponse(HttpVersion.HTTP_1_1, 200, "OK");
+        Mockito.when(this.conn.getHttpResponse()).thenReturn(response);
+        Mockito.doThrow(httpex).when(this.exchangeHandler).responseReceived(response);
+
+        this.protocolHandler.responseReceived(this.conn);
+
+        Mockito.verify(this.conn).shutdown();
+        Mockito.verify(this.exchangeHandler).failed(httpex);
+    }
+
+    @Test
+    public void testResponseContentInput() throws Exception {
+        HttpExchange httpExchange = this.protocolHandler.new HttpExchange();
+        httpExchange.setHandler(this.exchangeHandler);
+        this.connContext.setAttribute(HttpAsyncClientProtocolHandler.HTTP_EXCHNAGE, httpExchange);
+        Mockito.when(this.decoder.isCompleted()).thenReturn(false);
+
+        this.protocolHandler.inputReady(this.conn, this.decoder);
+
+        Mockito.verify(this.exchangeHandler).consumeContent(this.decoder, this.conn);
+        Assert.assertEquals(MessageState.BODY_STREAM, httpExchange.getResponseState());
+    }
+
+    @Test
+    public void testResponseContentOutputCompleted() throws Exception {
+        HttpExchange httpExchange = this.protocolHandler.new HttpExchange();
+        HttpRequest request = new BasicHttpRequest("GET", "/");
+        httpExchange.setRequest(request);
+        BasicHttpResponse response = new BasicHttpResponse(HttpVersion.HTTP_1_1, 200, "OK");
+        httpExchange.setResponse(response);
+        httpExchange.setHandler(this.exchangeHandler);
+        this.connContext.setAttribute(HttpAsyncClientProtocolHandler.HTTP_EXCHNAGE, httpExchange);
+        Mockito.when(this.reuseStrategy.keepAlive(response, this.exchangeContext)).thenReturn(true);
+        Mockito.when(this.exchangeHandler.getConnectionReuseStrategy()).thenReturn(this.reuseStrategy);
+        Mockito.when(this.decoder.isCompleted()).thenReturn(true);
+
+        this.protocolHandler.inputReady(this.conn, this.decoder);
+
+        Assert.assertEquals(MessageState.READY, httpExchange.getRequestState());
+        Assert.assertEquals(MessageState.READY, httpExchange.getResponseState());
+        Mockito.verify(this.exchangeHandler).consumeContent(this.decoder, this.conn);
+        Mockito.verify(this.exchangeHandler).responseCompleted(this.exchangeContext);
+        Mockito.verify(this.conn, Mockito.never()).close();
+    }
+
+    @Test
+    public void testResponseInvalidState() throws Exception {
+        HttpExchange httpExchange = this.protocolHandler.new HttpExchange();
+        HttpRequest request = new BasicHttpRequest("GET", "/");
+        httpExchange.setRequest(request);
+        BasicHttpResponse response = new BasicHttpResponse(HttpVersion.HTTP_1_1, 200, "OK");
+        httpExchange.setResponse(response);
+        httpExchange.invalidate();
+        httpExchange.setHandler(this.exchangeHandler);
+        this.connContext.setAttribute(HttpAsyncClientProtocolHandler.HTTP_EXCHNAGE, httpExchange);
+        Mockito.when(this.decoder.isCompleted()).thenReturn(true);
+
+        this.protocolHandler.inputReady(this.conn, this.decoder);
+
+        Assert.assertEquals(MessageState.READY, httpExchange.getRequestState());
+        Assert.assertEquals(MessageState.READY, httpExchange.getResponseState());
+        Mockito.verify(this.exchangeHandler).consumeContent(this.decoder, this.conn);
+        Mockito.verify(this.conn).close();
+        Mockito.verify(this.exchangeHandler, Mockito.never()).getConnectionReuseStrategy();
+    }
+
+    @Test
+    public void testResponseNoKeepAlive() throws Exception {
+        HttpExchange httpExchange = this.protocolHandler.new HttpExchange();
+        HttpRequest request = new BasicHttpRequest("GET", "/");
+        httpExchange.setRequest(request);
+        BasicHttpResponse response = new BasicHttpResponse(HttpVersion.HTTP_1_1, 200, "OK");
+        httpExchange.setResponse(response);
+        httpExchange.setHandler(this.exchangeHandler);
+        this.connContext.setAttribute(HttpAsyncClientProtocolHandler.HTTP_EXCHNAGE, httpExchange);
+        Mockito.when(this.reuseStrategy.keepAlive(response, this.exchangeContext)).thenReturn(false);
+        Mockito.when(this.exchangeHandler.getConnectionReuseStrategy()).thenReturn(this.reuseStrategy);
+        Mockito.when(this.decoder.isCompleted()).thenReturn(true);
+
+        this.protocolHandler.inputReady(this.conn, this.decoder);
+
+        Assert.assertEquals(MessageState.READY, httpExchange.getRequestState());
+        Assert.assertEquals(MessageState.READY, httpExchange.getResponseState());
+        Mockito.verify(this.exchangeHandler).consumeContent(this.decoder, this.conn);
+        Mockito.verify(this.exchangeHandler).responseCompleted(this.exchangeContext);
+        Mockito.verify(this.conn).close();
+    }
+
+    @Test
+    public void testResponseContentRuntimeException() throws Exception {
+        RuntimeException runtimeEx = new RuntimeException();
+        HttpExchange httpExchange = this.protocolHandler.new HttpExchange();
+        httpExchange.setHandler(this.exchangeHandler);
+        this.connContext.setAttribute(HttpAsyncClientProtocolHandler.HTTP_EXCHNAGE, httpExchange);
+        Mockito.doThrow(runtimeEx).when(this.exchangeHandler).consumeContent(this.decoder, this.conn);
+
+        try {
+            this.protocolHandler.inputReady(this.conn, this.decoder);
+            Assert.fail("RuntimeException expected");
+        } catch (RuntimeException ex) {
+            Mockito.verify(this.conn).shutdown();
+            Mockito.verify(this.exchangeHandler).failed(ex);
+        }
+    }
+
+    @Test
+    public void testResponseContentIOException() throws Exception {
+        IOException ioex = new IOException();
+        HttpExchange httpExchange = this.protocolHandler.new HttpExchange();
+        httpExchange.setHandler(this.exchangeHandler);
+        this.connContext.setAttribute(HttpAsyncClientProtocolHandler.HTTP_EXCHNAGE, httpExchange);
+        Mockito.doThrow(ioex).when(this.exchangeHandler).consumeContent(this.decoder, this.conn);
+
+        this.protocolHandler.inputReady(this.conn, this.decoder);
+
+        Mockito.verify(this.conn).shutdown();
+        Mockito.verify(this.exchangeHandler).failed(ioex);
+    }
+
+    @Test
+    public void testTimeoutNoHandler() throws Exception {
+        HttpExchange httpExchange = this.protocolHandler.new HttpExchange();
+        this.connContext.setAttribute(HttpAsyncClientProtocolHandler.HTTP_EXCHNAGE, httpExchange);
+
+        this.protocolHandler.timeout(this.conn);
+
+        Mockito.verify(this.conn).shutdown();
+    }
+
+    @Test
+    public void testExpectContinueTimeout() throws Exception {
+        HttpExchange httpExchange = this.protocolHandler.new HttpExchange();
+        httpExchange.setRequestState(MessageState.ACK_EXPECTED);
+        httpExchange.setTimeout(1000);
+        httpExchange.setHandler(this.exchangeHandler);
+        this.connContext.setAttribute(HttpAsyncClientProtocolHandler.HTTP_EXCHNAGE, httpExchange);
+
+        this.protocolHandler.timeout(this.conn);
+
+        Assert.assertEquals(MessageState.BODY_STREAM, httpExchange.getRequestState());
+        Mockito.verify(this.conn).setSocketTimeout(1000);
+        Mockito.verify(this.conn).requestOutput();
+    }
+
+    @Test
+    public void testTimeoutActiveConnection() throws Exception {
+        HttpExchange httpExchange = this.protocolHandler.new HttpExchange();
+        httpExchange.setRequestState(MessageState.BODY_STREAM);
+        httpExchange.setHandler(this.exchangeHandler);
+        this.connContext.setAttribute(HttpAsyncClientProtocolHandler.HTTP_EXCHNAGE, httpExchange);
+        Mockito.when(this.conn.getStatus()).thenReturn(NHttpConnection.ACTIVE, NHttpConnection.CLOSED);
+
+        this.protocolHandler.timeout(this.conn);
+
+        Assert.assertEquals(MessageState.BODY_STREAM, httpExchange.getRequestState());
+        Mockito.verify(this.exchangeHandler).failed(Mockito.any(SocketTimeoutException.class));
+        Mockito.verify(this.conn).close();
+        Mockito.verify(this.conn, Mockito.never()).setSocketTimeout(Mockito.anyInt());
+    }
+
+    @Test
+    public void testTimeoutActiveConnectionBufferedData() throws Exception {
+        HttpExchange httpExchange = this.protocolHandler.new HttpExchange();
+        httpExchange.setRequestState(MessageState.BODY_STREAM);
+        httpExchange.setHandler(this.exchangeHandler);
+        this.connContext.setAttribute(HttpAsyncClientProtocolHandler.HTTP_EXCHNAGE, httpExchange);
+        Mockito.when(this.conn.getStatus()).thenReturn(NHttpConnection.ACTIVE, NHttpConnection.CLOSING);
+
+        this.protocolHandler.timeout(this.conn);
+
+        Assert.assertEquals(MessageState.BODY_STREAM, httpExchange.getRequestState());
+        Mockito.verify(this.exchangeHandler).failed(Mockito.any(SocketTimeoutException.class));
+        Mockito.verify(this.conn).close();
+        Mockito.verify(this.conn).setSocketTimeout(250);
+    }
+
+    @Test
+    public void testTimeoutClosingConnection() throws Exception {
+        HttpExchange httpExchange = this.protocolHandler.new HttpExchange();
+        httpExchange.setRequestState(MessageState.BODY_STREAM);
+        httpExchange.setHandler(this.exchangeHandler);
+        this.connContext.setAttribute(HttpAsyncClientProtocolHandler.HTTP_EXCHNAGE, httpExchange);
+        Mockito.when(this.conn.getStatus()).thenReturn(NHttpConnection.CLOSING, NHttpConnection.CLOSED);
+
+        this.protocolHandler.timeout(this.conn);
+
+        Assert.assertEquals(MessageState.BODY_STREAM, httpExchange.getRequestState());
+        Mockito.verify(this.exchangeHandler).failed(Mockito.any(SocketTimeoutException.class));
+        Mockito.verify(this.conn).shutdown();
+    }
+
+    @Test
+    public void testTimeoutRuntimeException() throws Exception {
+        RuntimeException runtimeEx = new RuntimeException();
+        HttpExchange httpExchange = this.protocolHandler.new HttpExchange();
+        httpExchange.setHandler(this.exchangeHandler);
+        this.connContext.setAttribute(HttpAsyncClientProtocolHandler.HTTP_EXCHNAGE, httpExchange);
+        Mockito.doThrow(runtimeEx).when(this.exchangeHandler).failed(Mockito.any(SocketTimeoutException.class));
+
+        try {
+            this.protocolHandler.timeout(this.conn);
+            Assert.fail("RuntimeException expected");
+        } catch (RuntimeException ex) {
+            Mockito.verify(this.conn).shutdown();
+            Mockito.verify(this.exchangeHandler).failed(ex);
+        }
+    }
+
+    @Test
+    public void testExchangeDone() throws Exception {
+        HttpExchange httpExchange = this.protocolHandler.new HttpExchange();
+        HttpRequest request = new BasicHttpRequest("GET", "/");
+        httpExchange.setRequest(request);
+        BasicHttpResponse response = new BasicHttpResponse(HttpVersion.HTTP_1_1, 200, "OK");
+        httpExchange.setResponse(response);
+        httpExchange.setHandler(this.exchangeHandler);
+        this.connContext.setAttribute(HttpAsyncClientProtocolHandler.HTTP_EXCHNAGE, httpExchange);
+        Mockito.when(this.exchangeHandler.isDone()).thenReturn(true);
+
+        Assert.assertEquals("request state: READY; request: GET / HTTP/1.1; " +
+                "response state: READY; response: HTTP/1.1 200 OK; valid: true;",
+                httpExchange.toString());
+
+        this.protocolHandler.requestReady(this.conn);
+
+        Assert.assertEquals(MessageState.READY, httpExchange.getRequestState());
+        Assert.assertEquals(MessageState.READY, httpExchange.getResponseState());
+        Assert.assertNull(httpExchange.getHandler());
+    }
+
+}

Propchange: httpcomponents/httpcore/trunk/httpcore-nio/src/test/java/org/apache/http/nio/protocol/TestHttpAsyncClientProtocolHandler.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: httpcomponents/httpcore/trunk/httpcore-nio/src/test/java/org/apache/http/nio/protocol/TestHttpAsyncClientProtocolHandler.java
------------------------------------------------------------------------------
    svn:keywords = Date Revision

Propchange: httpcomponents/httpcore/trunk/httpcore-nio/src/test/java/org/apache/http/nio/protocol/TestHttpAsyncClientProtocolHandler.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain