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 2012/12/08 20:59:26 UTC

svn commit: r1418743 [5/6] - in /httpcomponents/httpclient/trunk: httpclient-cache/src/main/java/org/apache/http/impl/client/cache/ httpclient-cache/src/main/java/org/apache/http/impl/client/cache/memcached/ httpclient-cache/src/test/java/org/apache/ht...

Modified: httpcomponents/httpclient/trunk/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestProtocolRequirements.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestProtocolRequirements.java?rev=1418743&r1=1418742&r2=1418743&view=diff
==============================================================================
--- httpcomponents/httpclient/trunk/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestProtocolRequirements.java (original)
+++ httpcomponents/httpclient/trunk/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestProtocolRequirements.java Sat Dec  8 19:59:24 2012
@@ -45,7 +45,11 @@ import org.apache.http.HttpVersion;
 import org.apache.http.ProtocolVersion;
 import org.apache.http.client.ClientProtocolException;
 import org.apache.http.client.cache.HttpCacheEntry;
+import org.apache.http.client.methods.CloseableHttpResponse;
+import org.apache.http.client.methods.HttpExecutionAware;
 import org.apache.http.client.methods.HttpRequestWrapper;
+import org.apache.http.client.protocol.HttpClientContext;
+import org.apache.http.conn.routing.HttpRoute;
 import org.apache.http.entity.BasicHttpEntity;
 import org.apache.http.entity.ByteArrayEntity;
 import org.apache.http.impl.cookie.DateUtils;
@@ -54,7 +58,6 @@ import org.apache.http.message.BasicHttp
 import org.apache.http.message.BasicHttpRequest;
 import org.apache.http.message.BasicHttpResponse;
 import org.apache.http.protocol.HTTP;
-import org.apache.http.protocol.HttpContext;
 import org.easymock.Capture;
 import org.easymock.classextension.EasyMock;
 import org.junit.Assert;
@@ -74,11 +77,15 @@ public class TestProtocolRequirements ex
 
     @Test
     public void testCacheMissOnGETUsesOriginResponse() throws Exception {
-        EasyMock.expect(mockBackend.execute(host, request, (HttpContext) null)).andReturn(
-                originResponse);
+        EasyMock.expect(
+                mockBackend.execute(
+                        EasyMock.eq(route),
+                        eqRequest(request),
+                        EasyMock.isA(HttpClientContext.class),
+                        EasyMock.<HttpExecutionAware>isNull())).andReturn(originResponse);
         replayMocks();
 
-        HttpResponse result = impl.execute(host, request);
+        HttpResponse result = impl.execute(route, request);
 
         verifyMocks();
         Assert.assertTrue(HttpTestUtils.semanticallyTransparent(originResponse, result));
@@ -100,13 +107,18 @@ public class TestProtocolRequirements ex
 
         // tunnel behavior: I don't muck with request or response in
         // any way
-        request = HttpRequestWrapper.wrap(new BasicHttpRequest("GET", "/foo", new ProtocolVersion("HTTP", 2, 13)));
+        request = HttpRequestWrapper.wrap(
+                new BasicHttpRequest("GET", "/foo", new ProtocolVersion("HTTP", 2, 13)));
 
-        EasyMock.expect(mockBackend.execute(host, request, (HttpContext) null)).andReturn(
-                originResponse);
+        EasyMock.expect(
+                mockBackend.execute(
+                        EasyMock.eq(route),
+                        eqRequest(request),
+                        EasyMock.isA(HttpClientContext.class),
+                        EasyMock.<HttpExecutionAware>isNull())).andReturn(originResponse);
         replayMocks();
 
-        HttpResponse result = impl.execute(host, request);
+        HttpResponse result = impl.execute(route, request);
 
         verifyMocks();
         Assert.assertSame(originResponse, result);
@@ -115,16 +127,21 @@ public class TestProtocolRequirements ex
     @Test
     public void testHigher1_XProtocolVersionsDowngradeTo1_1() throws Exception {
 
-        request = HttpRequestWrapper.wrap(new BasicHttpRequest("GET", "/foo", new ProtocolVersion("HTTP", 1, 2)));
+        request = HttpRequestWrapper.wrap(
+                new BasicHttpRequest("GET", "/foo", new ProtocolVersion("HTTP", 1, 2)));
 
-        HttpRequest downgraded = HttpRequestWrapper.wrap(new BasicHttpRequest("GET", "/foo", HttpVersion.HTTP_1_1));
+        HttpRequestWrapper downgraded = HttpRequestWrapper.wrap(
+                new BasicHttpRequest("GET", "/foo", HttpVersion.HTTP_1_1));
 
         EasyMock.expect(
-                mockBackend.execute(EasyMock.eq(host), eqRequest(downgraded),
-                        (HttpContext) EasyMock.isNull())).andReturn(originResponse);
+                mockBackend.execute(
+                        EasyMock.eq(route),
+                        eqRequest(downgraded),
+                        EasyMock.isA(HttpClientContext.class),
+                        EasyMock.<HttpExecutionAware>isNull())).andReturn(originResponse);
 
         replayMocks();
-        HttpResponse result = impl.execute(host, request);
+        HttpResponse result = impl.execute(route, request);
 
         verifyMocks();
         Assert.assertTrue(HttpTestUtils.semanticallyTransparent(originResponse, result));
@@ -142,15 +159,20 @@ public class TestProtocolRequirements ex
     @Test
     public void testRequestsWithLowerProtocolVersionsGetUpgradedTo1_1() throws Exception {
 
-        request = HttpRequestWrapper.wrap(new BasicHttpRequest("GET", "/foo", new ProtocolVersion("HTTP", 1, 0)));
-        HttpRequest upgraded = HttpRequestWrapper.wrap(new BasicHttpRequest("GET", "/foo", HttpVersion.HTTP_1_1));
+        request = HttpRequestWrapper.wrap(
+                new BasicHttpRequest("GET", "/foo", new ProtocolVersion("HTTP", 1, 0)));
+        HttpRequestWrapper upgraded = HttpRequestWrapper.wrap(
+                new BasicHttpRequest("GET", "/foo", HttpVersion.HTTP_1_1));
 
         EasyMock.expect(
-                mockBackend.execute(EasyMock.eq(host), eqRequest(upgraded), (HttpContext) EasyMock
-                        .isNull())).andReturn(originResponse);
+                mockBackend.execute(
+                        EasyMock.eq(route),
+                        eqRequest(upgraded),
+                        EasyMock.isA(HttpClientContext.class),
+                        EasyMock.<HttpExecutionAware>isNull())).andReturn(originResponse);
         replayMocks();
 
-        HttpResponse result = impl.execute(host, request);
+        HttpResponse result = impl.execute(route, request);
 
         verifyMocks();
         Assert.assertTrue(HttpTestUtils.semanticallyTransparent(originResponse, result));
@@ -166,8 +188,8 @@ public class TestProtocolRequirements ex
      */
     @Test
     public void testLowerOriginResponsesUpgradedToOurVersion1_1() throws Exception {
-        originResponse = new BasicHttpResponse(new ProtocolVersion("HTTP", 1, 2), HttpStatus.SC_OK,
-                "OK");
+        originResponse = Proxies.enhanceResponse(
+                new BasicHttpResponse(new ProtocolVersion("HTTP", 1, 2), HttpStatus.SC_OK, "OK"));
         originResponse.setHeader("Date", DateUtils.formatDate(new Date()));
         originResponse.setHeader("Server", "MockOrigin/1.0");
         originResponse.setEntity(body);
@@ -175,11 +197,14 @@ public class TestProtocolRequirements ex
         // not testing this internal behavior in this test, just want
         // to check the protocol version that comes out the other end
         EasyMock.expect(
-                mockBackend.execute(EasyMock.isA(HttpHost.class), EasyMock.isA(HttpRequest.class),
-                        (HttpContext) EasyMock.isNull())).andReturn(originResponse);
+                mockBackend.execute(
+                        EasyMock.isA(HttpRoute.class),
+                        EasyMock.isA(HttpRequestWrapper.class),
+                        EasyMock.isA(HttpClientContext.class),
+                        EasyMock.<HttpExecutionAware>isNull())).andReturn(originResponse);
         replayMocks();
 
-        HttpResponse result = impl.execute(host, request);
+        HttpResponse result = impl.execute(route, request);
 
         verifyMocks();
         Assert.assertEquals(HttpVersion.HTTP_1_1, result.getProtocolVersion());
@@ -187,14 +212,18 @@ public class TestProtocolRequirements ex
 
     @Test
     public void testResponseToA1_0RequestShouldUse1_1() throws Exception {
-        request = HttpRequestWrapper.wrap(new BasicHttpRequest("GET", "/foo", new ProtocolVersion("HTTP", 1, 0)));
+        request = HttpRequestWrapper.wrap(
+                new BasicHttpRequest("GET", "/foo", new ProtocolVersion("HTTP", 1, 0)));
 
         EasyMock.expect(
-                mockBackend.execute(EasyMock.isA(HttpHost.class), EasyMock.isA(HttpRequest.class),
-                        (HttpContext) EasyMock.isNull())).andReturn(originResponse);
+                mockBackend.execute(
+                        EasyMock.isA(HttpRoute.class),
+                        EasyMock.isA(HttpRequestWrapper.class),
+                        EasyMock.isA(HttpClientContext.class),
+                        EasyMock.<HttpExecutionAware>isNull())).andReturn(originResponse);
         replayMocks();
 
-        HttpResponse result = impl.execute(host, request);
+        HttpResponse result = impl.execute(route, request);
 
         verifyMocks();
         Assert.assertEquals(HttpVersion.HTTP_1_1, result.getProtocolVersion());
@@ -206,20 +235,25 @@ public class TestProtocolRequirements ex
      */
     @Test
     public void testForwardsUnknownHeadersOnRequestsFromHigherProtocolVersions() throws Exception {
-        request = HttpRequestWrapper.wrap(new BasicHttpRequest("GET", "/foo", new ProtocolVersion("HTTP", 1, 2)));
+        request = HttpRequestWrapper.wrap(
+                new BasicHttpRequest("GET", "/foo", new ProtocolVersion("HTTP", 1, 2)));
         request.removeHeaders("Connection");
         request.addHeader("X-Unknown-Header", "some-value");
 
-        HttpRequestWrapper downgraded = HttpRequestWrapper.wrap(new BasicHttpRequest("GET", "/foo", HttpVersion.HTTP_1_1));
+        HttpRequestWrapper downgraded = HttpRequestWrapper.wrap(
+                new BasicHttpRequest("GET", "/foo", HttpVersion.HTTP_1_1));
         downgraded.removeHeaders("Connection");
         downgraded.addHeader("X-Unknown-Header", "some-value");
 
         EasyMock.expect(
-                mockBackend.execute(EasyMock.isA(HttpHost.class), eqRequest(downgraded),
-                        (HttpContext) EasyMock.isNull())).andReturn(originResponse);
+                mockBackend.execute(
+                        EasyMock.isA(HttpRoute.class),
+                        eqRequest(downgraded),
+                        EasyMock.isA(HttpClientContext.class),
+                        EasyMock.<HttpExecutionAware>isNull())).andReturn(originResponse);
         replayMocks();
 
-        impl.execute(host, request);
+        impl.execute(route, request);
 
         verifyMocks();
     }
@@ -233,14 +267,18 @@ public class TestProtocolRequirements ex
 
         originResponse.setHeader("Transfer-Encoding", "identity");
 
-        request = HttpRequestWrapper.wrap(new BasicHttpRequest("GET", "/foo", new ProtocolVersion("HTTP", 1, 0)));
+        request = HttpRequestWrapper.wrap(
+                new BasicHttpRequest("GET", "/foo", new ProtocolVersion("HTTP", 1, 0)));
 
         EasyMock.expect(
-                mockBackend.execute(EasyMock.isA(HttpHost.class), EasyMock.isA(HttpRequest.class),
-                        (HttpContext) EasyMock.isNull())).andReturn(originResponse);
+                mockBackend.execute(
+                        EasyMock.isA(HttpRoute.class),
+                        EasyMock.isA(HttpRequestWrapper.class),
+                        EasyMock.isA(HttpClientContext.class),
+                        EasyMock.<HttpExecutionAware>isNull())).andReturn(originResponse);
         replayMocks();
 
-        HttpResponse result = impl.execute(host, request);
+        HttpResponse result = impl.execute(route, request);
 
         verifyMocks();
 
@@ -261,16 +299,19 @@ public class TestProtocolRequirements ex
      * these field values when a message is forwarded."
      * http://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.2
      */
-    private void testOrderOfMultipleHeadersIsPreservedOnRequests(String h, HttpRequest request)
+    private void testOrderOfMultipleHeadersIsPreservedOnRequests(String h, HttpRequestWrapper request)
             throws Exception {
-        Capture<HttpRequest> reqCapture = new Capture<HttpRequest>();
+        Capture<HttpRequestWrapper> reqCapture = new Capture<HttpRequestWrapper>();
 
         EasyMock.expect(
-                mockBackend.execute(EasyMock.isA(HttpHost.class), EasyMock.capture(reqCapture),
-                        (HttpContext) EasyMock.isNull())).andReturn(originResponse);
+                mockBackend.execute(
+                        EasyMock.isA(HttpRoute.class),
+                        EasyMock.capture(reqCapture),
+                        EasyMock.isA(HttpClientContext.class),
+                        EasyMock.<HttpExecutionAware>isNull())).andReturn(originResponse);
         replayMocks();
 
-        impl.execute(host, request);
+        impl.execute(route, request);
 
         verifyMocks();
 
@@ -317,7 +358,7 @@ public class TestProtocolRequirements ex
         put.addHeader("Allow", "GET, HEAD");
         put.addHeader("Allow", "DELETE");
         put.addHeader("Content-Length", "128");
-        testOrderOfMultipleHeadersIsPreservedOnRequests("Allow", put);
+        testOrderOfMultipleHeadersIsPreservedOnRequests("Allow", HttpRequestWrapper.wrap(put));
     }
 
     @Test
@@ -335,7 +376,7 @@ public class TestProtocolRequirements ex
         post.addHeader("Content-Encoding", "gzip");
         post.addHeader("Content-Encoding", "compress");
         post.addHeader("Content-Length", "128");
-        testOrderOfMultipleHeadersIsPreservedOnRequests("Content-Encoding", post);
+        testOrderOfMultipleHeadersIsPreservedOnRequests("Content-Encoding", HttpRequestWrapper.wrap(post));
     }
 
     @Test
@@ -346,7 +387,7 @@ public class TestProtocolRequirements ex
         post.addHeader("Content-Language", "mi");
         post.addHeader("Content-Language", "en");
         post.addHeader("Content-Length", "128");
-        testOrderOfMultipleHeadersIsPreservedOnRequests("Content-Language", post);
+        testOrderOfMultipleHeadersIsPreservedOnRequests("Content-Language", HttpRequestWrapper.wrap(post));
     }
 
     @Test
@@ -357,7 +398,7 @@ public class TestProtocolRequirements ex
         post.addHeader("Expect", "100-continue");
         post.addHeader("Expect", "x-expect=true");
         post.addHeader("Content-Length", "128");
-        testOrderOfMultipleHeadersIsPreservedOnRequests("Expect", post);
+        testOrderOfMultipleHeadersIsPreservedOnRequests("Expect", HttpRequestWrapper.wrap(post));
     }
 
     @Test
@@ -383,11 +424,14 @@ public class TestProtocolRequirements ex
 
     private void testOrderOfMultipleHeadersIsPreservedOnResponses(String h) throws Exception {
         EasyMock.expect(
-                mockBackend.execute(EasyMock.isA(HttpHost.class), EasyMock.isA(HttpRequest.class),
-                        (HttpContext) EasyMock.isNull())).andReturn(originResponse);
+                mockBackend.execute(
+                        EasyMock.isA(HttpRoute.class),
+                        EasyMock.isA(HttpRequestWrapper.class),
+                        EasyMock.isA(HttpClientContext.class),
+                        EasyMock.<HttpExecutionAware>isNull())).andReturn(originResponse);
         replayMocks();
 
-        HttpResponse result = impl.execute(host, request);
+        HttpResponse result = impl.execute(route, request);
 
         verifyMocks();
 
@@ -399,7 +443,8 @@ public class TestProtocolRequirements ex
 
     @Test
     public void testOrderOfMultipleAllowHeadersIsPreservedOnResponses() throws Exception {
-        originResponse = new BasicHttpResponse(HttpVersion.HTTP_1_1, 405, "Method Not Allowed");
+        originResponse = Proxies.enhanceResponse(
+                new BasicHttpResponse(HttpVersion.HTTP_1_1, 405, "Method Not Allowed"));
         originResponse.addHeader("Allow", "HEAD");
         originResponse.addHeader("Allow", "DELETE");
         testOrderOfMultipleHeadersIsPreservedOnResponses("Allow");
@@ -459,19 +504,23 @@ public class TestProtocolRequirements ex
 
         emptyMockCacheExpectsNoPuts();
 
-        originResponse = new BasicHttpResponse(HttpVersion.HTTP_1_1, code, "Moo");
+        originResponse = Proxies.enhanceResponse(
+                new BasicHttpResponse(HttpVersion.HTTP_1_1, code, "Moo"));
         originResponse.setHeader("Date", DateUtils.formatDate(new Date()));
         originResponse.setHeader("Server", "MockOrigin/1.0");
         originResponse.setHeader("Cache-Control", "max-age=3600");
         originResponse.setEntity(body);
 
         EasyMock.expect(
-                mockBackend.execute(EasyMock.isA(HttpHost.class), EasyMock.isA(HttpRequest.class),
-                        (HttpContext) EasyMock.isNull())).andReturn(originResponse);
+                mockBackend.execute(
+                        EasyMock.isA(HttpRoute.class),
+                        EasyMock.isA(HttpRequestWrapper.class),
+                        EasyMock.isA(HttpClientContext.class),
+                        EasyMock.<HttpExecutionAware>isNull())).andReturn(originResponse);
 
         replayMocks();
 
-        impl.execute(host, request);
+        impl.execute(route, request);
 
         // in particular, there were no storage calls on the cache
         verifyMocks();
@@ -505,14 +554,17 @@ public class TestProtocolRequirements ex
     @Test
     public void testUnknownHeadersOnRequestsAreForwarded() throws Exception {
         request.addHeader("X-Unknown-Header", "blahblah");
-        Capture<HttpRequest> reqCap = new Capture<HttpRequest>();
+        Capture<HttpRequestWrapper> reqCap = new Capture<HttpRequestWrapper>();
         EasyMock.expect(
-                mockBackend.execute(EasyMock.isA(HttpHost.class), EasyMock.capture(reqCap),
-                        (HttpContext) EasyMock.anyObject())).andReturn(originResponse);
+                mockBackend.execute(
+                        EasyMock.isA(HttpRoute.class),
+                        EasyMock.capture(reqCap),
+                        EasyMock.isA(HttpClientContext.class),
+                        EasyMock.<HttpExecutionAware>isNull())).andReturn(originResponse);
 
         replayMocks();
 
-        impl.execute(host, request);
+        impl.execute(route, request);
 
         verifyMocks();
         HttpRequest forwarded = reqCap.getValue();
@@ -525,12 +577,15 @@ public class TestProtocolRequirements ex
     public void testUnknownHeadersOnResponsesAreForwarded() throws Exception {
         originResponse.addHeader("X-Unknown-Header", "blahblah");
         EasyMock.expect(
-                mockBackend.execute(EasyMock.isA(HttpHost.class), EasyMock.isA(HttpRequest.class),
-                        (HttpContext) EasyMock.isNull())).andReturn(originResponse);
+                mockBackend.execute(
+                        EasyMock.isA(HttpRoute.class),
+                        EasyMock.isA(HttpRequestWrapper.class),
+                        EasyMock.isA(HttpClientContext.class),
+                        EasyMock.<HttpExecutionAware>isNull())).andReturn(originResponse);
 
         replayMocks();
 
-        HttpResponse result = impl.execute(host, request);
+        HttpResponse result = impl.execute(route, request);
 
         verifyMocks();
         Header[] hdrs = result.getHeaders("X-Unknown-Header");
@@ -553,20 +608,22 @@ public class TestProtocolRequirements ex
         post.setHeader("Content-Length", "128");
         post.setEntity(new BasicHttpEntity());
 
-        Capture<HttpEntityEnclosingRequest> reqCap = new Capture<HttpEntityEnclosingRequest>();
+        Capture<HttpRequestWrapper> reqCap = new Capture<HttpRequestWrapper>();
 
         EasyMock.expect(
-                mockBackend.execute(EasyMock.eq(host), EasyMock.capture(reqCap),
-                        (HttpContext) EasyMock.isNull())).andReturn(originResponse);
+                mockBackend.execute(
+                        EasyMock.eq(route),
+                        EasyMock.capture(reqCap),
+                        EasyMock.isA(HttpClientContext.class),
+                        EasyMock.<HttpExecutionAware>isNull())).andReturn(originResponse);
 
         replayMocks();
 
-        impl.execute(host, post);
+        impl.execute(route, HttpRequestWrapper.wrap(post));
 
         verifyMocks();
 
-        HttpEntityEnclosingRequest forwarded = reqCap.getValue();
-        Assert.assertTrue(forwarded.expectContinue());
+        HttpRequestWrapper forwarded = reqCap.getValue();
         boolean foundExpect = false;
         for (Header h : forwarded.getHeaders("Expect")) {
             for (HeaderElement elt : h.getElements()) {
@@ -594,20 +651,22 @@ public class TestProtocolRequirements ex
         post.setHeader("Content-Length", "128");
         post.setEntity(new BasicHttpEntity());
 
-        Capture<HttpEntityEnclosingRequest> reqCap = new Capture<HttpEntityEnclosingRequest>();
+        Capture<HttpRequestWrapper> reqCap = new Capture<HttpRequestWrapper>();
 
         EasyMock.expect(
-                mockBackend.execute(EasyMock.eq(host), EasyMock.capture(reqCap),
-                        (HttpContext) EasyMock.isNull())).andReturn(originResponse);
+                mockBackend.execute(
+                        EasyMock.eq(route),
+                        EasyMock.capture(reqCap),
+                        EasyMock.isA(HttpClientContext.class),
+                        EasyMock.<HttpExecutionAware>isNull())).andReturn(originResponse);
 
         replayMocks();
 
-        impl.execute(host, post);
+        impl.execute(route, HttpRequestWrapper.wrap(post));
 
         verifyMocks();
 
-        HttpEntityEnclosingRequest forwarded = reqCap.getValue();
-        Assert.assertFalse(forwarded.expectContinue());
+        HttpRequestWrapper forwarded = reqCap.getValue();
         boolean foundExpect = false;
         for (Header h : forwarded.getHeaders("Expect")) {
             for (HeaderElement elt : h.getElements()) {
@@ -630,13 +689,16 @@ public class TestProtocolRequirements ex
     @Test
     public void testExpect100ContinueIsNotSentIfThereIsNoRequestBody() throws Exception {
         request.addHeader("Expect", "100-continue");
-        Capture<HttpRequest> reqCap = new Capture<HttpRequest>();
+        Capture<HttpRequestWrapper> reqCap = new Capture<HttpRequestWrapper>();
         EasyMock.expect(
-                mockBackend.execute(EasyMock.eq(host), EasyMock.capture(reqCap),
-                        (HttpContext) EasyMock.isNull())).andReturn(originResponse);
+                mockBackend.execute(
+                        EasyMock.eq(route),
+                        EasyMock.capture(reqCap),
+                        EasyMock.isA(HttpClientContext.class),
+                        EasyMock.<HttpExecutionAware>isNull())).andReturn(originResponse);
 
         replayMocks();
-        impl.execute(host, request);
+        impl.execute(route, request);
         verifyMocks();
         HttpRequest forwarded = reqCap.getValue();
         boolean foundExpectContinue = false;
@@ -690,16 +752,20 @@ public class TestProtocolRequirements ex
         post.setEntity(body);
         post.setHeader("Content-Length", "128");
 
-        originResponse = new BasicHttpResponse(HttpVersion.HTTP_1_1, 100, "Continue");
+        originResponse = Proxies.enhanceResponse(
+                new BasicHttpResponse(HttpVersion.HTTP_1_1, 100, "Continue"));
         EasyMock.expect(
-                mockBackend.execute(EasyMock.eq(host), EasyMock.isA(HttpRequest.class),
-                        (HttpContext) EasyMock.isNull())).andReturn(originResponse);
+                mockBackend.execute(
+                        EasyMock.eq(route),
+                        EasyMock.isA(HttpRequestWrapper.class),
+                        EasyMock.isA(HttpClientContext.class),
+                        EasyMock.<HttpExecutionAware>isNull())).andReturn(originResponse);
         replayMocks();
 
         try {
             // if a 100 response gets up to us from the HttpClient
             // backend, we can't really handle it at that point
-            impl.execute(host, post);
+            impl.execute(route, HttpRequestWrapper.wrap(post));
             Assert.fail("should have thrown an exception");
         } catch (ClientProtocolException expected) {
         }
@@ -719,12 +785,15 @@ public class TestProtocolRequirements ex
         originResponse.addHeader("Cache-Control", "max-age=3600");
 
         EasyMock.expect(
-                mockBackend.execute(EasyMock.eq(host), EasyMock.isA(HttpRequest.class),
-                        (HttpContext) EasyMock.isNull())).andReturn(originResponse);
+                mockBackend.execute(
+                        EasyMock.eq(route),
+                        EasyMock.isA(HttpRequestWrapper.class),
+                        EasyMock.isA(HttpClientContext.class),
+                        EasyMock.<HttpExecutionAware>isNull())).andReturn(originResponse);
 
         replayMocks();
 
-        impl.execute(host, request);
+        impl.execute(route, request);
 
         verifyMocks();
     }
@@ -743,11 +812,14 @@ public class TestProtocolRequirements ex
         originResponse.setHeader("Content-Length", "0");
 
         EasyMock.expect(
-                mockBackend.execute(EasyMock.eq(host), EasyMock.isA(HttpRequest.class),
-                        (HttpContext) EasyMock.isNull())).andReturn(originResponse);
+                mockBackend.execute(
+                        EasyMock.eq(route),
+                        EasyMock.isA(HttpRequestWrapper.class),
+                        EasyMock.isA(HttpClientContext.class),
+                        EasyMock.<HttpExecutionAware>isNull())).andReturn(originResponse);
         replayMocks();
 
-        HttpResponse result = impl.execute(host, request);
+        HttpResponse result = impl.execute(route, request);
 
         verifyMocks();
         Header contentLength = result.getFirstHeader("Content-Length");
@@ -771,7 +843,7 @@ public class TestProtocolRequirements ex
         request.setHeader("Max-Forwards", "0");
 
         replayMocks();
-        impl.execute(host, request);
+        impl.execute(route, request);
         verifyMocks();
     }
 
@@ -787,14 +859,17 @@ public class TestProtocolRequirements ex
         request = HttpRequestWrapper.wrap(new BasicHttpRequest("OPTIONS", "*", HttpVersion.HTTP_1_1));
         request.setHeader("Max-Forwards", "7");
 
-        Capture<HttpRequest> cap = new Capture<HttpRequest>();
+        Capture<HttpRequestWrapper> cap = new Capture<HttpRequestWrapper>();
 
         EasyMock.expect(
-                mockBackend.execute(EasyMock.eq(host), EasyMock.capture(cap),
-                        (HttpContext) EasyMock.isNull())).andReturn(originResponse);
+                mockBackend.execute(
+                        EasyMock.eq(route),
+                        EasyMock.capture(cap),
+                        EasyMock.isA(HttpClientContext.class),
+                        EasyMock.<HttpExecutionAware>isNull())).andReturn(originResponse);
 
         replayMocks();
-        impl.execute(host, request);
+        impl.execute(route, request);
         verifyMocks();
 
         HttpRequest captured = cap.getValue();
@@ -810,13 +885,16 @@ public class TestProtocolRequirements ex
     @Test
     public void testDoesNotAddAMaxForwardsHeaderToForwardedOPTIONSRequests() throws Exception {
         request = HttpRequestWrapper.wrap(new BasicHttpRequest("OPTIONS", "/", HttpVersion.HTTP_1_1));
-        Capture<HttpRequest> reqCap = new Capture<HttpRequest>();
+        Capture<HttpRequestWrapper> reqCap = new Capture<HttpRequestWrapper>();
         EasyMock.expect(
-                mockBackend.execute(EasyMock.eq(host), EasyMock.capture(reqCap),
-                        (HttpContext) EasyMock.isNull())).andReturn(originResponse);
+                mockBackend.execute(
+                        EasyMock.eq(route),
+                        EasyMock.capture(reqCap),
+                        EasyMock.isA(HttpClientContext.class),
+                        EasyMock.<HttpExecutionAware>isNull())).andReturn(originResponse);
 
         replayMocks();
-        impl.execute(host, request);
+        impl.execute(route, request);
         verifyMocks();
 
         HttpRequest forwarded = reqCap.getValue();
@@ -833,12 +911,15 @@ public class TestProtocolRequirements ex
     public void testResponseToAHEADRequestMustNotHaveABody() throws Exception {
         request = HttpRequestWrapper.wrap(new BasicHttpRequest("HEAD", "/", HttpVersion.HTTP_1_1));
         EasyMock.expect(
-                mockBackend.execute(EasyMock.eq(host), EasyMock.isA(HttpRequest.class),
-                        (HttpContext) EasyMock.isNull())).andReturn(originResponse);
+                mockBackend.execute(
+                        EasyMock.eq(route),
+                        EasyMock.isA(HttpRequestWrapper.class),
+                        EasyMock.isA(HttpClientContext.class),
+                        EasyMock.<HttpExecutionAware>isNull())).andReturn(originResponse);
 
         replayMocks();
 
-        HttpResponse result = impl.execute(host, request);
+        HttpResponse result = impl.execute(route, request);
 
         verifyMocks();
 
@@ -857,39 +938,52 @@ public class TestProtocolRequirements ex
             String oldVal, String newVal) throws Exception {
 
         // put something cacheable in the cache
-        HttpRequest req1 = HttpRequestWrapper.wrap(new BasicHttpRequest("GET", "/", HttpVersion.HTTP_1_1));
+        HttpRequestWrapper req1 = HttpRequestWrapper.wrap(
+                new BasicHttpRequest("GET", "/", HttpVersion.HTTP_1_1));
         HttpResponse resp1 = HttpTestUtils.make200Response();
         resp1.addHeader("Cache-Control", "max-age=3600");
         resp1.setHeader(eHeader, oldVal);
 
         // get a head that penetrates the cache
-        HttpRequest req2 = HttpRequestWrapper.wrap(new BasicHttpRequest("HEAD", "/", HttpVersion.HTTP_1_1));
+        HttpRequestWrapper req2 = HttpRequestWrapper.wrap(
+                new BasicHttpRequest("HEAD", "/", HttpVersion.HTTP_1_1));
         req2.addHeader("Cache-Control", "no-cache");
         HttpResponse resp2 = HttpTestUtils.make200Response();
         resp2.setEntity(null);
         resp2.setHeader(eHeader, newVal);
 
         // next request doesn't tolerate stale entry
-        HttpRequest req3 = HttpRequestWrapper.wrap(new BasicHttpRequest("GET", "/", HttpVersion.HTTP_1_1));
+        HttpRequestWrapper req3 = HttpRequestWrapper.wrap(
+                new BasicHttpRequest("GET", "/", HttpVersion.HTTP_1_1));
         req3.addHeader("Cache-Control", "max-stale=0");
         HttpResponse resp3 = HttpTestUtils.make200Response();
         resp3.setHeader(eHeader, newVal);
 
         EasyMock.expect(
-                mockBackend.execute(EasyMock.eq(host), eqRequest(req1), (HttpContext) EasyMock
-                        .isNull())).andReturn(resp1);
-        EasyMock.expect(
-                mockBackend.execute(EasyMock.eq(host), eqRequest(req2), (HttpContext) EasyMock
-                        .isNull())).andReturn(resp2);
-        EasyMock.expect(
-                mockBackend.execute(EasyMock.eq(host), EasyMock.isA(HttpRequest.class),
-                        (HttpContext) EasyMock.isNull())).andReturn(resp3);
+                mockBackend.execute(
+                        EasyMock.eq(route),
+                        eqRequest(req1),
+                        EasyMock.isA(HttpClientContext.class),
+                        EasyMock.<HttpExecutionAware>isNull())).andReturn(originResponse);
+        EasyMock.expect(
+                mockBackend.execute(
+                        EasyMock.eq(route),
+                        eqRequest(req2),
+                        EasyMock.isA(HttpClientContext.class),
+                        EasyMock.<HttpExecutionAware>isNull())).andReturn(originResponse);
+        EasyMock.expect(
+                mockBackend.execute(
+                        EasyMock.eq(route),
+                        EasyMock.isA(HttpRequestWrapper.class),
+                        EasyMock.isA(HttpClientContext.class),
+                        EasyMock.<HttpExecutionAware>isNull())).andReturn(
+                                Proxies.enhanceResponse(resp3));
 
         replayMocks();
 
-        impl.execute(host, req1);
-        impl.execute(host, req2);
-        impl.execute(host, req3);
+        impl.execute(route, req1);
+        impl.execute(route, req2);
+        impl.execute(route, req3);
 
         verifyMocks();
     }
@@ -941,12 +1035,15 @@ public class TestProtocolRequirements ex
         originResponse.removeHeaders("Expires");
 
         EasyMock.expect(
-                mockBackend.execute(EasyMock.isA(HttpHost.class), EasyMock.isA(HttpRequest.class),
-                        (HttpContext) EasyMock.isNull())).andReturn(originResponse);
+                mockBackend.execute(
+                        EasyMock.isA(HttpRoute.class),
+                        EasyMock.isA(HttpRequestWrapper.class),
+                        EasyMock.isA(HttpClientContext.class),
+                        EasyMock.<HttpExecutionAware>isNull())).andReturn(originResponse);
 
         replayMocks();
 
-        impl.execute(host, post);
+        impl.execute(route, HttpRequestWrapper.wrap(post));
 
         verifyMocks();
     }
@@ -968,12 +1065,15 @@ public class TestProtocolRequirements ex
         originResponse.setHeader("Cache-Control", "max-age=3600");
 
         EasyMock.expect(
-                mockBackend.execute(EasyMock.isA(HttpHost.class), EasyMock.isA(HttpRequest.class),
-                        (HttpContext) EasyMock.isNull())).andReturn(originResponse);
+                mockBackend.execute(
+                        EasyMock.isA(HttpRoute.class),
+                        EasyMock.isA(HttpRequestWrapper.class),
+                        EasyMock.isA(HttpClientContext.class),
+                        EasyMock.<HttpExecutionAware>isNull())).andReturn(originResponse);
 
         replayMocks();
 
-        impl.execute(host, put);
+        impl.execute(route, HttpRequestWrapper.wrap(put));
 
         verifyMocks();
     }
@@ -991,12 +1091,15 @@ public class TestProtocolRequirements ex
         originResponse.setHeader("Cache-Control", "max-age=3600");
 
         EasyMock.expect(
-                mockBackend.execute(EasyMock.isA(HttpHost.class), EasyMock.isA(HttpRequest.class),
-                        (HttpContext) EasyMock.isNull())).andReturn(originResponse);
+                mockBackend.execute(
+                        EasyMock.isA(HttpRoute.class),
+                        EasyMock.isA(HttpRequestWrapper.class),
+                        EasyMock.isA(HttpClientContext.class),
+                        EasyMock.<HttpExecutionAware>isNull())).andReturn(originResponse);
 
         replayMocks();
 
-        impl.execute(host, request);
+        impl.execute(route, request);
 
         verifyMocks();
     }
@@ -1013,14 +1116,17 @@ public class TestProtocolRequirements ex
         trace.setEntity(HttpTestUtils.makeBody(entityLength));
         trace.setHeader("Content-Length", Integer.toString(entityLength));
 
-        Capture<HttpRequest> reqCap = new Capture<HttpRequest>();
+        Capture<HttpRequestWrapper> reqCap = new Capture<HttpRequestWrapper>();
 
         EasyMock.expect(
-                mockBackend.execute(EasyMock.eq(host), EasyMock.capture(reqCap),
-                        (HttpContext) EasyMock.isNull())).andReturn(originResponse);
+                mockBackend.execute(
+                        EasyMock.eq(route),
+                        EasyMock.capture(reqCap),
+                        EasyMock.isA(HttpClientContext.class),
+                        EasyMock.<HttpExecutionAware>isNull())).andReturn(originResponse);
 
         replayMocks();
-        impl.execute(host, trace);
+        impl.execute(route, HttpRequestWrapper.wrap(trace));
         verifyMocks();
 
         HttpRequest forwarded = reqCap.getValue();
@@ -1046,12 +1152,15 @@ public class TestProtocolRequirements ex
         originResponse.setHeader("Cache-Control", "max-age=3600");
 
         EasyMock.expect(
-                mockBackend.execute(EasyMock.isA(HttpHost.class), EasyMock.isA(HttpRequest.class),
-                        (HttpContext) EasyMock.isNull())).andReturn(originResponse);
+                mockBackend.execute(
+                        EasyMock.isA(HttpRoute.class),
+                        EasyMock.isA(HttpRequestWrapper.class),
+                        EasyMock.isA(HttpClientContext.class),
+                        EasyMock.<HttpExecutionAware>isNull())).andReturn(originResponse);
 
         replayMocks();
 
-        impl.execute(host, request);
+        impl.execute(route, request);
 
         verifyMocks();
     }
@@ -1064,16 +1173,20 @@ public class TestProtocolRequirements ex
      */
     @Test
     public void test204ResponsesDoNotContainMessageBodies() throws Exception {
-        originResponse = new BasicHttpResponse(HttpVersion.HTTP_1_1, HttpStatus.SC_NO_CONTENT, "No Content");
+        originResponse = Proxies.enhanceResponse(
+                new BasicHttpResponse(HttpVersion.HTTP_1_1, HttpStatus.SC_NO_CONTENT, "No Content"));
         originResponse.setEntity(HttpTestUtils.makeBody(entityLength));
 
         EasyMock.expect(
-                mockBackend.execute(EasyMock.isA(HttpHost.class), EasyMock.isA(HttpRequest.class),
-                        (HttpContext) EasyMock.isNull())).andReturn(originResponse);
+                mockBackend.execute(
+                        EasyMock.isA(HttpRoute.class),
+                        EasyMock.isA(HttpRequestWrapper.class),
+                        EasyMock.isA(HttpClientContext.class),
+                        EasyMock.<HttpExecutionAware>isNull())).andReturn(originResponse);
 
         replayMocks();
 
-        HttpResponse result = impl.execute(host, request);
+        HttpResponse result = impl.execute(route, request);
 
         verifyMocks();
 
@@ -1087,17 +1200,20 @@ public class TestProtocolRequirements ex
      */
     @Test
     public void test205ResponsesDoNotContainMessageBodies() throws Exception {
-        originResponse = new BasicHttpResponse(HttpVersion.HTTP_1_1, HttpStatus.SC_RESET_CONTENT,
-                "Reset Content");
+        originResponse = Proxies.enhanceResponse(
+                new BasicHttpResponse(HttpVersion.HTTP_1_1, HttpStatus.SC_RESET_CONTENT, "Reset Content"));
         originResponse.setEntity(HttpTestUtils.makeBody(entityLength));
 
         EasyMock.expect(
-                mockBackend.execute(EasyMock.isA(HttpHost.class), EasyMock.isA(HttpRequest.class),
-                        (HttpContext) EasyMock.isNull())).andReturn(originResponse);
+                mockBackend.execute(
+                        EasyMock.isA(HttpRoute.class),
+                        EasyMock.isA(HttpRequestWrapper.class),
+                        EasyMock.isA(HttpClientContext.class),
+                        EasyMock.<HttpExecutionAware>isNull())).andReturn(originResponse);
 
         replayMocks();
 
-        HttpResponse result = impl.execute(host, request);
+        HttpResponse result = impl.execute(route, request);
 
         verifyMocks();
 
@@ -1127,19 +1243,21 @@ public class TestProtocolRequirements ex
     public void test206ResponseGeneratedFromCacheMustHaveContentRangeOrMultipartByteRangesContentType()
             throws Exception {
 
-        HttpRequest req1 = HttpRequestWrapper.wrap(new BasicHttpRequest("GET", "/", HttpVersion.HTTP_1_1));
+        HttpRequestWrapper req1 = HttpRequestWrapper.wrap(
+                new BasicHttpRequest("GET", "/", HttpVersion.HTTP_1_1));
         HttpResponse resp1 = HttpTestUtils.make200Response();
         resp1.setHeader("ETag", "\"etag\"");
         resp1.setHeader("Cache-Control", "max-age=3600");
 
-        HttpRequest req2 = HttpRequestWrapper.wrap(new BasicHttpRequest("GET", "/", HttpVersion.HTTP_1_1));
+        HttpRequestWrapper req2 = HttpRequestWrapper.wrap(
+                new BasicHttpRequest("GET", "/", HttpVersion.HTTP_1_1));
         req2.setHeader("Range", "bytes=0-50");
 
-        backendExpectsAnyRequest().andReturn(resp1).times(1, 2);
+        backendExpectsAnyRequestAndReturn(resp1).times(1, 2);
 
         replayMocks();
-        impl.execute(host, req1);
-        HttpResponse result = impl.execute(host, req2);
+        impl.execute(route, req1);
+        HttpResponse result = impl.execute(route, req2);
         verifyMocks();
 
         if (HttpStatus.SC_PARTIAL_CONTENT == result.getStatusLine().getStatusCode()) {
@@ -1157,19 +1275,21 @@ public class TestProtocolRequirements ex
     public void test206ResponseGeneratedFromCacheMustHaveABodyThatMatchesContentLengthHeaderIfPresent()
             throws Exception {
 
-        HttpRequest req1 = HttpRequestWrapper.wrap(new BasicHttpRequest("GET", "/", HttpVersion.HTTP_1_1));
+        HttpRequestWrapper req1 = HttpRequestWrapper.wrap(
+                new BasicHttpRequest("GET", "/", HttpVersion.HTTP_1_1));
         HttpResponse resp1 = HttpTestUtils.make200Response();
         resp1.setHeader("ETag", "\"etag\"");
         resp1.setHeader("Cache-Control", "max-age=3600");
 
-        HttpRequest req2 = HttpRequestWrapper.wrap(new BasicHttpRequest("GET", "/", HttpVersion.HTTP_1_1));
+        HttpRequestWrapper req2 = HttpRequestWrapper.wrap(
+                new BasicHttpRequest("GET", "/", HttpVersion.HTTP_1_1));
         req2.setHeader("Range", "bytes=0-50");
 
-        backendExpectsAnyRequest().andReturn(resp1).times(1, 2);
+        backendExpectsAnyRequestAndReturn(resp1).times(1, 2);
 
         replayMocks();
-        impl.execute(host, req1);
-        HttpResponse result = impl.execute(host, req2);
+        impl.execute(route, req1);
+        HttpResponse result = impl.execute(route, req2);
         verifyMocks();
 
         if (HttpStatus.SC_PARTIAL_CONTENT == result.getStatusLine().getStatusCode()) {
@@ -1189,19 +1309,21 @@ public class TestProtocolRequirements ex
 
     @Test
     public void test206ResponseGeneratedFromCacheMustHaveDateHeader() throws Exception {
-        HttpRequest req1 = HttpRequestWrapper.wrap(new BasicHttpRequest("GET", "/", HttpVersion.HTTP_1_1));
+        HttpRequestWrapper req1 = HttpRequestWrapper.wrap(
+                new BasicHttpRequest("GET", "/", HttpVersion.HTTP_1_1));
         HttpResponse resp1 = HttpTestUtils.make200Response();
         resp1.setHeader("ETag", "\"etag\"");
         resp1.setHeader("Cache-Control", "max-age=3600");
 
-        HttpRequest req2 = HttpRequestWrapper.wrap(new BasicHttpRequest("GET", "/", HttpVersion.HTTP_1_1));
+        HttpRequestWrapper req2 = HttpRequestWrapper.wrap(
+                new BasicHttpRequest("GET", "/", HttpVersion.HTTP_1_1));
         req2.setHeader("Range", "bytes=0-50");
 
-        backendExpectsAnyRequest().andReturn(resp1).times(1, 2);
+        backendExpectsAnyRequestAndReturn(resp1).times(1, 2);
 
         replayMocks();
-        impl.execute(host, req1);
-        HttpResponse result = impl.execute(host, req2);
+        impl.execute(route, req1);
+        HttpResponse result = impl.execute(route, req2);
         verifyMocks();
 
         if (HttpStatus.SC_PARTIAL_CONTENT == result.getStatusLine().getStatusCode()) {
@@ -1212,8 +1334,8 @@ public class TestProtocolRequirements ex
     @Test
     public void test206ResponseReturnedToClientMustHaveDateHeader() throws Exception {
         request.addHeader("Range", "bytes=0-50");
-        originResponse = new BasicHttpResponse(HttpVersion.HTTP_1_1, HttpStatus.SC_PARTIAL_CONTENT,
-                "Partial Content");
+        originResponse = Proxies.enhanceResponse(
+                new BasicHttpResponse(HttpVersion.HTTP_1_1, HttpStatus.SC_PARTIAL_CONTENT, "Partial Content"));
         originResponse.setHeader("Date", DateUtils.formatDate(new Date()));
         originResponse.setHeader("Server", "MockOrigin/1.0");
         originResponse.setEntity(HttpTestUtils.makeBody(500));
@@ -1221,12 +1343,15 @@ public class TestProtocolRequirements ex
         originResponse.removeHeaders("Date");
 
         EasyMock.expect(
-                mockBackend.execute(EasyMock.isA(HttpHost.class), EasyMock.isA(HttpRequest.class),
-                        (HttpContext) EasyMock.isNull())).andReturn(originResponse);
+                mockBackend.execute(
+                        EasyMock.isA(HttpRoute.class),
+                        EasyMock.isA(HttpRequestWrapper.class),
+                        EasyMock.isA(HttpClientContext.class),
+                        EasyMock.<HttpExecutionAware>isNull())).andReturn(originResponse);
 
         replayMocks();
 
-        HttpResponse result = impl.execute(host, request);
+        HttpResponse result = impl.execute(route, request);
         Assert.assertTrue(result.getStatusLine().getStatusCode() != HttpStatus.SC_PARTIAL_CONTENT
                 || result.getFirstHeader("Date") != null);
 
@@ -1235,20 +1360,22 @@ public class TestProtocolRequirements ex
 
     @Test
     public void test206ContainsETagIfA200ResponseWouldHaveIncludedIt() throws Exception {
-        HttpRequest req1 = HttpRequestWrapper.wrap(new BasicHttpRequest("GET", "/", HttpVersion.HTTP_1_1));
+        HttpRequestWrapper req1 = HttpRequestWrapper.wrap(
+                new BasicHttpRequest("GET", "/", HttpVersion.HTTP_1_1));
 
         originResponse.addHeader("Cache-Control", "max-age=3600");
         originResponse.addHeader("ETag", "\"etag1\"");
 
-        HttpRequest req2 = HttpRequestWrapper.wrap(new BasicHttpRequest("GET", "/", HttpVersion.HTTP_1_1));
+        HttpRequestWrapper req2 = HttpRequestWrapper.wrap(
+                new BasicHttpRequest("GET", "/", HttpVersion.HTTP_1_1));
         req2.addHeader("Range", "bytes=0-50");
 
         backendExpectsAnyRequest().andReturn(originResponse).times(1, 2);
 
         replayMocks();
 
-        impl.execute(host, req1);
-        HttpResponse result = impl.execute(host, req2);
+        impl.execute(route, req1);
+        HttpResponse result = impl.execute(route, req2);
 
         verifyMocks();
 
@@ -1259,20 +1386,22 @@ public class TestProtocolRequirements ex
 
     @Test
     public void test206ContainsContentLocationIfA200ResponseWouldHaveIncludedIt() throws Exception {
-        HttpRequest req1 = HttpRequestWrapper.wrap(new BasicHttpRequest("GET", "/", HttpVersion.HTTP_1_1));
+        HttpRequestWrapper req1 = HttpRequestWrapper.wrap(
+                new BasicHttpRequest("GET", "/", HttpVersion.HTTP_1_1));
 
         originResponse.addHeader("Cache-Control", "max-age=3600");
         originResponse.addHeader("Content-Location", "http://foo.example.com/other/url");
 
-        HttpRequest req2 = HttpRequestWrapper.wrap(new BasicHttpRequest("GET", "/", HttpVersion.HTTP_1_1));
+        HttpRequestWrapper req2 = HttpRequestWrapper.wrap(
+                new BasicHttpRequest("GET", "/", HttpVersion.HTTP_1_1));
         req2.addHeader("Range", "bytes=0-50");
 
         backendExpectsAnyRequest().andReturn(originResponse).times(1, 2);
 
         replayMocks();
 
-        impl.execute(host, req1);
-        HttpResponse result = impl.execute(host, req2);
+        impl.execute(route, req1);
+        HttpResponse result = impl.execute(route, req2);
 
         verifyMocks();
 
@@ -1284,7 +1413,8 @@ public class TestProtocolRequirements ex
     @Test
     public void test206ResponseIncludesVariantHeadersIfValueMightDiffer() throws Exception {
 
-        HttpRequest req1 = HttpRequestWrapper.wrap(new BasicHttpRequest("GET", "/", HttpVersion.HTTP_1_1));
+        HttpRequestWrapper req1 = HttpRequestWrapper.wrap(
+                new BasicHttpRequest("GET", "/", HttpVersion.HTTP_1_1));
         req1.addHeader("Accept-Encoding", "gzip");
 
         Date now = new Date();
@@ -1293,7 +1423,8 @@ public class TestProtocolRequirements ex
         originResponse.addHeader("Expires", DateUtils.formatDate(inOneHour));
         originResponse.addHeader("Vary", "Accept-Encoding");
 
-        HttpRequest req2 = HttpRequestWrapper.wrap(new BasicHttpRequest("GET", "/", HttpVersion.HTTP_1_1));
+        HttpRequestWrapper req2 = HttpRequestWrapper.wrap(
+                new BasicHttpRequest("GET", "/", HttpVersion.HTTP_1_1));
         req2.addHeader("Cache-Control", "no-cache");
         req2.addHeader("Accept-Encoding", "gzip");
         Date nextSecond = new Date(now.getTime() + 1000L);
@@ -1305,18 +1436,19 @@ public class TestProtocolRequirements ex
         originResponse2.setHeader("Expires", DateUtils.formatDate(inTwoHoursPlusASec));
         originResponse2.setHeader("Vary", "Accept-Encoding");
 
-        HttpRequest req3 = HttpRequestWrapper.wrap(new BasicHttpRequest("GET", "/", HttpVersion.HTTP_1_1));
+        HttpRequestWrapper req3 = HttpRequestWrapper.wrap(
+                new BasicHttpRequest("GET", "/", HttpVersion.HTTP_1_1));
         req3.addHeader("Range", "bytes=0-50");
         req3.addHeader("Accept-Encoding", "gzip");
 
         backendExpectsAnyRequest().andReturn(originResponse);
-        backendExpectsAnyRequest().andReturn(originResponse2).times(1, 2);
+        backendExpectsAnyRequestAndReturn(originResponse2).times(1, 2);
 
         replayMocks();
 
-        impl.execute(host, req1);
-        impl.execute(host, req2);
-        HttpResponse result = impl.execute(host, req3);
+        impl.execute(route, req1);
+        impl.execute(route, req2);
+        HttpResponse result = impl.execute(route, req3);
 
         verifyMocks();
 
@@ -1339,11 +1471,12 @@ public class TestProtocolRequirements ex
     public void test206ResponseToConditionalRangeRequestDoesNotIncludeOtherEntityHeaders()
             throws Exception {
 
-        HttpRequest req1 = HttpRequestWrapper.wrap(new BasicHttpRequest("GET", "/", HttpVersion.HTTP_1_1));
+        HttpRequestWrapper req1 = HttpRequestWrapper.wrap(
+                new BasicHttpRequest("GET", "/", HttpVersion.HTTP_1_1));
 
         Date now = new Date();
         Date oneHourAgo = new Date(now.getTime() - 3600 * 1000L);
-        originResponse = HttpTestUtils.make200Response();
+        originResponse = Proxies.enhanceResponse(HttpTestUtils.make200Response());
         originResponse.addHeader("Allow", "GET,HEAD");
         originResponse.addHeader("Cache-Control", "max-age=3600");
         originResponse.addHeader("Content-Language", "en");
@@ -1354,7 +1487,8 @@ public class TestProtocolRequirements ex
         originResponse.addHeader("Last-Modified", DateUtils.formatDate(oneHourAgo));
         originResponse.addHeader("ETag", "W/\"weak-tag\"");
 
-        HttpRequest req2 = HttpRequestWrapper.wrap(new BasicHttpRequest("GET", "/", HttpVersion.HTTP_1_1));
+        HttpRequestWrapper req2 = HttpRequestWrapper.wrap(
+                new BasicHttpRequest("GET", "/", HttpVersion.HTTP_1_1));
         req2.addHeader("If-Range", "W/\"weak-tag\"");
         req2.addHeader("Range", "bytes=0-50");
 
@@ -1362,8 +1496,8 @@ public class TestProtocolRequirements ex
 
         replayMocks();
 
-        impl.execute(host, req1);
-        HttpResponse result = impl.execute(host, req2);
+        impl.execute(route, req1);
+        HttpResponse result = impl.execute(route, req2);
 
         verifyMocks();
 
@@ -1387,7 +1521,8 @@ public class TestProtocolRequirements ex
     public void test206ResponseToIfRangeWithStrongValidatorReturnsAllEntityHeaders()
             throws Exception {
 
-        HttpRequest req1 = HttpRequestWrapper.wrap(new BasicHttpRequest("GET", "/", HttpVersion.HTTP_1_1));
+        HttpRequestWrapper req1 = HttpRequestWrapper.wrap(
+                new BasicHttpRequest("GET", "/", HttpVersion.HTTP_1_1));
 
         Date now = new Date();
         Date oneHourAgo = new Date(now.getTime() - 3600 * 1000L);
@@ -1401,7 +1536,8 @@ public class TestProtocolRequirements ex
         originResponse.addHeader("Last-Modified", DateUtils.formatDate(oneHourAgo));
         originResponse.addHeader("ETag", "\"strong-tag\"");
 
-        HttpRequest req2 = HttpRequestWrapper.wrap(new BasicHttpRequest("GET", "/", HttpVersion.HTTP_1_1));
+        HttpRequestWrapper req2 = HttpRequestWrapper.wrap(
+                new BasicHttpRequest("GET", "/", HttpVersion.HTTP_1_1));
         req2.addHeader("If-Range", "\"strong-tag\"");
         req2.addHeader("Range", "bytes=0-50");
 
@@ -1409,8 +1545,8 @@ public class TestProtocolRequirements ex
 
         replayMocks();
 
-        impl.execute(host, req1);
-        HttpResponse result = impl.execute(host, req2);
+        impl.execute(route, req1);
+        HttpResponse result = impl.execute(route, req2);
 
         verifyMocks();
 
@@ -1439,7 +1575,8 @@ public class TestProtocolRequirements ex
 
         Date now = new Date();
 
-        HttpRequest req1 = HttpRequestWrapper.wrap(new BasicHttpRequest("GET", "/", HttpVersion.HTTP_1_1));
+        HttpRequestWrapper req1 = HttpRequestWrapper.wrap(
+                new BasicHttpRequest("GET", "/", HttpVersion.HTTP_1_1));
         HttpResponse resp1 = HttpTestUtils.make200Response();
         resp1.setHeader("Cache-Control", "max-age=3600");
         resp1.setHeader("ETag", "\"etag1\"");
@@ -1449,7 +1586,8 @@ public class TestProtocolRequirements ex
         }
         resp1.setEntity(new ByteArrayEntity(bytes1));
 
-        HttpRequest req2 = HttpRequestWrapper.wrap(new BasicHttpRequest("GET", "/", HttpVersion.HTTP_1_1));
+        HttpRequestWrapper req2 = HttpRequestWrapper.wrap(
+                new BasicHttpRequest("GET", "/", HttpVersion.HTTP_1_1));
         req2.setHeader("Cache-Control", "no-cache");
         req2.setHeader("Range", "bytes=0-50");
 
@@ -1467,7 +1605,8 @@ public class TestProtocolRequirements ex
         resp2.setEntity(new ByteArrayEntity(bytes2));
 
         Date inTwoSeconds = new Date(now.getTime() + 2000L);
-        HttpRequest req3 = HttpRequestWrapper.wrap(new BasicHttpRequest("GET", "/", HttpVersion.HTTP_1_1));
+        HttpRequestWrapper req3 = HttpRequestWrapper.wrap(
+                new BasicHttpRequest("GET", "/", HttpVersion.HTTP_1_1));
         HttpResponse resp3 = HttpTestUtils.make200Response();
         resp3.setHeader("Date", DateUtils.formatDate(inTwoSeconds));
         resp3.setHeader("Cache-Control", "max-age=3600");
@@ -1479,19 +1618,31 @@ public class TestProtocolRequirements ex
         resp3.setEntity(new ByteArrayEntity(bytes3));
 
         EasyMock.expect(
-                mockBackend.execute(EasyMock.isA(HttpHost.class), EasyMock.isA(HttpRequest.class),
-                        (HttpContext) EasyMock.isNull())).andReturn(resp1);
-        EasyMock.expect(
-                mockBackend.execute(EasyMock.isA(HttpHost.class), EasyMock.isA(HttpRequest.class),
-                        (HttpContext) EasyMock.isNull())).andReturn(resp2);
-        EasyMock.expect(
-                mockBackend.execute(EasyMock.isA(HttpHost.class), EasyMock.isA(HttpRequest.class),
-                        (HttpContext) EasyMock.isNull())).andReturn(resp3).times(0, 1);
-        replayMocks();
-
-        impl.execute(host, req1);
-        impl.execute(host, req2);
-        HttpResponse result = impl.execute(host, req3);
+                mockBackend.execute(
+                        EasyMock.isA(HttpRoute.class),
+                        EasyMock.isA(HttpRequestWrapper.class),
+                        EasyMock.isA(HttpClientContext.class),
+                        EasyMock.<HttpExecutionAware>isNull())).andReturn(
+                                Proxies.enhanceResponse(resp1));
+        EasyMock.expect(
+                mockBackend.execute(
+                        EasyMock.isA(HttpRoute.class),
+                        EasyMock.isA(HttpRequestWrapper.class),
+                        EasyMock.isA(HttpClientContext.class),
+                        EasyMock.<HttpExecutionAware>isNull())).andReturn(
+                                Proxies.enhanceResponse(resp2));
+        EasyMock.expect(
+                mockBackend.execute(
+                        EasyMock.isA(HttpRoute.class),
+                        EasyMock.isA(HttpRequestWrapper.class),
+                        EasyMock.isA(HttpClientContext.class),
+                        EasyMock.<HttpExecutionAware>isNull())).andReturn(
+                                Proxies.enhanceResponse(resp3)).times(0, 1);
+        replayMocks();
+
+        impl.execute(route, req1);
+        impl.execute(route, req2);
+        HttpResponse result = impl.execute(route, req3);
 
         verifyMocks();
 
@@ -1515,7 +1666,8 @@ public class TestProtocolRequirements ex
 
         Date now = new Date();
 
-        HttpRequest req1 = HttpRequestWrapper.wrap(new BasicHttpRequest("GET", "/", HttpVersion.HTTP_1_1));
+        HttpRequestWrapper req1 = HttpRequestWrapper.wrap(
+                new BasicHttpRequest("GET", "/", HttpVersion.HTTP_1_1));
         HttpResponse resp1 = HttpTestUtils.make200Response();
         Date oneHourAgo = new Date(now.getTime() - 3600L);
         resp1.setHeader("Cache-Control", "max-age=3600");
@@ -1526,7 +1678,8 @@ public class TestProtocolRequirements ex
         }
         resp1.setEntity(new ByteArrayEntity(bytes1));
 
-        HttpRequest req2 = HttpRequestWrapper.wrap(new BasicHttpRequest("GET", "/", HttpVersion.HTTP_1_1));
+        HttpRequestWrapper req2 = HttpRequestWrapper.wrap(
+                new BasicHttpRequest("GET", "/", HttpVersion.HTTP_1_1));
         req2.setHeader("Cache-Control", "no-cache");
         req2.setHeader("Range", "bytes=0-50");
 
@@ -1544,7 +1697,8 @@ public class TestProtocolRequirements ex
         resp2.setEntity(new ByteArrayEntity(bytes2));
 
         Date inTwoSeconds = new Date(now.getTime() + 2000L);
-        HttpRequest req3 = HttpRequestWrapper.wrap(new BasicHttpRequest("GET", "/", HttpVersion.HTTP_1_1));
+        HttpRequestWrapper req3 = HttpRequestWrapper.wrap(
+                new BasicHttpRequest("GET", "/", HttpVersion.HTTP_1_1));
         HttpResponse resp3 = HttpTestUtils.make200Response();
         resp3.setHeader("Date", DateUtils.formatDate(inTwoSeconds));
         resp3.setHeader("Cache-Control", "max-age=3600");
@@ -1556,19 +1710,31 @@ public class TestProtocolRequirements ex
         resp3.setEntity(new ByteArrayEntity(bytes3));
 
         EasyMock.expect(
-                mockBackend.execute(EasyMock.isA(HttpHost.class), EasyMock.isA(HttpRequest.class),
-                        (HttpContext) EasyMock.isNull())).andReturn(resp1);
-        EasyMock.expect(
-                mockBackend.execute(EasyMock.isA(HttpHost.class), EasyMock.isA(HttpRequest.class),
-                        (HttpContext) EasyMock.isNull())).andReturn(resp2);
-        EasyMock.expect(
-                mockBackend.execute(EasyMock.isA(HttpHost.class), EasyMock.isA(HttpRequest.class),
-                        (HttpContext) EasyMock.isNull())).andReturn(resp3).times(0, 1);
-        replayMocks();
-
-        impl.execute(host, req1);
-        impl.execute(host, req2);
-        HttpResponse result = impl.execute(host, req3);
+                mockBackend.execute(
+                        EasyMock.isA(HttpRoute.class),
+                        EasyMock.isA(HttpRequestWrapper.class),
+                        EasyMock.isA(HttpClientContext.class),
+                        EasyMock.<HttpExecutionAware>isNull())).andReturn(
+                                Proxies.enhanceResponse(resp1));
+        EasyMock.expect(
+                mockBackend.execute(
+                        EasyMock.isA(HttpRoute.class),
+                        EasyMock.isA(HttpRequestWrapper.class),
+                        EasyMock.isA(HttpClientContext.class),
+                        EasyMock.<HttpExecutionAware>isNull())).andReturn(
+                                Proxies.enhanceResponse(resp2));
+        EasyMock.expect(
+                mockBackend.execute(
+                        EasyMock.isA(HttpRoute.class),
+                        EasyMock.isA(HttpRequestWrapper.class),
+                        EasyMock.isA(HttpClientContext.class),
+                        EasyMock.<HttpExecutionAware>isNull())).andReturn(
+                                Proxies.enhanceResponse(resp3)).times(0, 1);
+        replayMocks();
+
+        impl.execute(route, req1);
+        impl.execute(route, req2);
+        HttpResponse result = impl.execute(route, req3);
 
         verifyMocks();
 
@@ -1599,11 +1765,13 @@ public class TestProtocolRequirements ex
         if (!impl.supportsRangeAndContentRangeHeaders()) {
             emptyMockCacheExpectsNoPuts();
 
-            request = HttpRequestWrapper.wrap(new BasicHttpRequest("GET", "/", HttpVersion.HTTP_1_1));
+            request = HttpRequestWrapper.wrap(
+                    new BasicHttpRequest("GET", "/", HttpVersion.HTTP_1_1));
             request.addHeader("Range", "bytes=0-50");
 
-            originResponse = new BasicHttpResponse(HttpVersion.HTTP_1_1, HttpStatus.SC_PARTIAL_CONTENT,
-                    "Partial Content");
+            originResponse = Proxies.enhanceResponse(
+                    new BasicHttpResponse(HttpVersion.HTTP_1_1, HttpStatus.SC_PARTIAL_CONTENT,
+                    "Partial Content"));
             originResponse.setHeader("Content-Range", "bytes 0-50/128");
             originResponse.setHeader("Cache-Control", "max-age=3600");
             byte[] bytes = new byte[51];
@@ -1611,12 +1779,15 @@ public class TestProtocolRequirements ex
             originResponse.setEntity(new ByteArrayEntity(bytes));
 
             EasyMock.expect(
-                    mockBackend.execute(EasyMock.isA(HttpHost.class), EasyMock
-                            .isA(HttpRequest.class), (HttpContext) EasyMock.isNull())).andReturn(
-                    originResponse);
+                    mockBackend.execute(
+                            EasyMock.isA(HttpRoute.class),
+                            EasyMock.isA(HttpRequestWrapper.class),
+                            EasyMock.isA(HttpClientContext.class),
+                            EasyMock.<HttpExecutionAware>isNull())).andReturn(
+                                    originResponse);
 
             replayMocks();
-            impl.execute(host, request);
+            impl.execute(route, request);
             verifyMocks();
         }
     }
@@ -1633,7 +1804,8 @@ public class TestProtocolRequirements ex
 
         request = HttpRequestWrapper.wrap(new BasicHttpRequest("GET", "/", HttpVersion.HTTP_1_1));
 
-        originResponse = new BasicHttpResponse(HttpVersion.HTTP_1_1, HttpStatus.SC_SEE_OTHER, "See Other");
+        originResponse = Proxies.enhanceResponse(
+                new BasicHttpResponse(HttpVersion.HTTP_1_1, HttpStatus.SC_SEE_OTHER, "See Other"));
         originResponse.setHeader("Date", DateUtils.formatDate(new Date()));
         originResponse.setHeader("Server", "MockServer/1.0");
         originResponse.setHeader("Cache-Control", "max-age=3600");
@@ -1642,11 +1814,14 @@ public class TestProtocolRequirements ex
         originResponse.setEntity(HttpTestUtils.makeBody(entityLength));
 
         EasyMock.expect(
-                mockBackend.execute(EasyMock.isA(HttpHost.class), EasyMock.isA(HttpRequest.class),
-                        (HttpContext) EasyMock.isNull())).andReturn(originResponse);
+                mockBackend.execute(
+                        EasyMock.isA(HttpRoute.class),
+                        EasyMock.isA(HttpRequestWrapper.class),
+                        EasyMock.isA(HttpClientContext.class),
+                        EasyMock.<HttpExecutionAware>isNull())).andReturn(originResponse);
 
         replayMocks();
-        impl.execute(host, request);
+        impl.execute(route, request);
         verifyMocks();
     }
 
@@ -1660,19 +1835,24 @@ public class TestProtocolRequirements ex
     public void test304ResponseDoesNotContainABody() throws Exception {
         request.setHeader("If-None-Match", "\"etag\"");
 
-        originResponse = new BasicHttpResponse(HttpVersion.HTTP_1_1, HttpStatus.SC_NOT_MODIFIED, "Not Modified");
+        originResponse = Proxies.enhanceResponse(
+                new BasicHttpResponse(HttpVersion.HTTP_1_1, HttpStatus.SC_NOT_MODIFIED,
+                        "Not Modified"));
         originResponse.setHeader("Date", DateUtils.formatDate(new Date()));
         originResponse.setHeader("Server", "MockServer/1.0");
         originResponse.setHeader("Content-Length", "128");
         originResponse.setEntity(HttpTestUtils.makeBody(entityLength));
 
         EasyMock.expect(
-                mockBackend.execute(EasyMock.isA(HttpHost.class), EasyMock.isA(HttpRequest.class),
-                        (HttpContext) EasyMock.isNull())).andReturn(originResponse);
+                mockBackend.execute(
+                        EasyMock.isA(HttpRoute.class),
+                        EasyMock.isA(HttpRequestWrapper.class),
+                        EasyMock.isA(HttpClientContext.class),
+                        EasyMock.<HttpExecutionAware>isNull())).andReturn(originResponse);
 
         replayMocks();
 
-        HttpResponse result = impl.execute(host, request);
+        HttpResponse result = impl.execute(route, request);
 
         verifyMocks();
 
@@ -1692,17 +1872,22 @@ public class TestProtocolRequirements ex
 
         request.setHeader("If-None-Match", "\"etag\"");
 
-        originResponse = new BasicHttpResponse(HttpVersion.HTTP_1_1, HttpStatus.SC_NOT_MODIFIED, "Not Modified");
+        originResponse = Proxies.enhanceResponse(
+                new BasicHttpResponse(HttpVersion.HTTP_1_1, HttpStatus.SC_NOT_MODIFIED,
+                        "Not Modified"));
         originResponse.setHeader("Date", DateUtils.formatDate(new Date()));
         originResponse.setHeader("Server", "MockServer/1.0");
         originResponse.setHeader("ETag", "\"etag\"");
 
         EasyMock.expect(
-                mockBackend.execute(EasyMock.isA(HttpHost.class), EasyMock.isA(HttpRequest.class),
-                        (HttpContext) EasyMock.isNull())).andReturn(originResponse);
+                mockBackend.execute(
+                        EasyMock.isA(HttpRoute.class),
+                        EasyMock.isA(HttpRequestWrapper.class),
+                        EasyMock.isA(HttpClientContext.class),
+                        EasyMock.<HttpExecutionAware>isNull())).andReturn(originResponse);
         replayMocks();
 
-        HttpResponse result = impl.execute(host, request);
+        HttpResponse result = impl.execute(route, request);
 
         verifyMocks();
         Assert.assertNotNull(result.getFirstHeader("Date"));
@@ -1711,20 +1896,25 @@ public class TestProtocolRequirements ex
     @Test
     public void test304ResponseGeneratedFromCacheIncludesDateHeader() throws Exception {
 
-        HttpRequest req1 = HttpRequestWrapper.wrap(new BasicHttpRequest("GET", "/", HttpVersion.HTTP_1_1));
+        HttpRequestWrapper req1 = HttpRequestWrapper.wrap(
+                new BasicHttpRequest("GET", "/", HttpVersion.HTTP_1_1));
         originResponse.setHeader("Cache-Control", "max-age=3600");
         originResponse.setHeader("ETag", "\"etag\"");
 
-        HttpRequest req2 = HttpRequestWrapper.wrap(new BasicHttpRequest("GET", "/", HttpVersion.HTTP_1_1));
+        HttpRequestWrapper req2 = HttpRequestWrapper.wrap(
+                new BasicHttpRequest("GET", "/", HttpVersion.HTTP_1_1));
         req2.setHeader("If-None-Match", "\"etag\"");
 
         EasyMock.expect(
-                mockBackend.execute(EasyMock.isA(HttpHost.class), EasyMock.isA(HttpRequest.class),
-                        (HttpContext) EasyMock.isNull())).andReturn(originResponse).times(1, 2);
+                mockBackend.execute(
+                        EasyMock.isA(HttpRoute.class),
+                        EasyMock.isA(HttpRequestWrapper.class),
+                        EasyMock.isA(HttpClientContext.class),
+                        EasyMock.<HttpExecutionAware>isNull())).andReturn(originResponse).times(1, 2);
         replayMocks();
 
-        impl.execute(host, req1);
-        HttpResponse result = impl.execute(host, req2);
+        impl.execute(route, req1);
+        HttpResponse result = impl.execute(route, req2);
 
         verifyMocks();
         if (result.getStatusLine().getStatusCode() == HttpStatus.SC_NOT_MODIFIED) {
@@ -1741,20 +1931,25 @@ public class TestProtocolRequirements ex
      */
     @Test
     public void test304ResponseGeneratedFromCacheIncludesEtagIfOriginResponseDid() throws Exception {
-        HttpRequest req1 = HttpRequestWrapper.wrap(new BasicHttpRequest("GET", "/", HttpVersion.HTTP_1_1));
+        HttpRequestWrapper req1 = HttpRequestWrapper.wrap(
+                new BasicHttpRequest("GET", "/", HttpVersion.HTTP_1_1));
         originResponse.setHeader("Cache-Control", "max-age=3600");
         originResponse.setHeader("ETag", "\"etag\"");
 
-        HttpRequest req2 = HttpRequestWrapper.wrap(new BasicHttpRequest("GET", "/", HttpVersion.HTTP_1_1));
+        HttpRequestWrapper req2 = HttpRequestWrapper.wrap(
+                new BasicHttpRequest("GET", "/", HttpVersion.HTTP_1_1));
         req2.setHeader("If-None-Match", "\"etag\"");
 
         EasyMock.expect(
-                mockBackend.execute(EasyMock.isA(HttpHost.class), EasyMock.isA(HttpRequest.class),
-                        (HttpContext) EasyMock.isNull())).andReturn(originResponse).times(1, 2);
+                mockBackend.execute(
+                        EasyMock.isA(HttpRoute.class),
+                        EasyMock.isA(HttpRequestWrapper.class),
+                        EasyMock.isA(HttpClientContext.class),
+                        EasyMock.<HttpExecutionAware>isNull())).andReturn(originResponse).times(1, 2);
         replayMocks();
 
-        impl.execute(host, req1);
-        HttpResponse result = impl.execute(host, req2);
+        impl.execute(route, req1);
+        HttpResponse result = impl.execute(route, req2);
 
         verifyMocks();
         if (result.getStatusLine().getStatusCode() == HttpStatus.SC_NOT_MODIFIED) {
@@ -1765,21 +1960,26 @@ public class TestProtocolRequirements ex
     @Test
     public void test304ResponseGeneratedFromCacheIncludesContentLocationIfOriginResponseDid()
             throws Exception {
-        HttpRequest req1 = HttpRequestWrapper.wrap(new BasicHttpRequest("GET", "/", HttpVersion.HTTP_1_1));
+        HttpRequestWrapper req1 = HttpRequestWrapper.wrap(
+                new BasicHttpRequest("GET", "/", HttpVersion.HTTP_1_1));
         originResponse.setHeader("Cache-Control", "max-age=3600");
         originResponse.setHeader("Content-Location", "http://foo.example.com/other");
         originResponse.setHeader("ETag", "\"etag\"");
 
-        HttpRequest req2 = HttpRequestWrapper.wrap(new BasicHttpRequest("GET", "/", HttpVersion.HTTP_1_1));
+        HttpRequestWrapper req2 = HttpRequestWrapper.wrap(
+                new BasicHttpRequest("GET", "/", HttpVersion.HTTP_1_1));
         req2.setHeader("If-None-Match", "\"etag\"");
 
         EasyMock.expect(
-                mockBackend.execute(EasyMock.isA(HttpHost.class), EasyMock.isA(HttpRequest.class),
-                        (HttpContext) EasyMock.isNull())).andReturn(originResponse).times(1, 2);
+                mockBackend.execute(
+                        EasyMock.isA(HttpRoute.class),
+                        EasyMock.isA(HttpRequestWrapper.class),
+                        EasyMock.isA(HttpClientContext.class),
+                        EasyMock.<HttpExecutionAware>isNull())).andReturn(originResponse).times(1, 2);
         replayMocks();
 
-        impl.execute(host, req1);
-        HttpResponse result = impl.execute(host, req2);
+        impl.execute(route, req1);
+        HttpResponse result = impl.execute(route, req2);
 
         verifyMocks();
         if (result.getStatusLine().getStatusCode() == HttpStatus.SC_NOT_MODIFIED) {
@@ -1801,7 +2001,8 @@ public class TestProtocolRequirements ex
         Date now = new Date();
         Date inTwoHours = new Date(now.getTime() + 2 * 3600 * 1000L);
 
-        HttpRequest req1 = HttpRequestWrapper.wrap(new BasicHttpRequest("GET", "/", HttpVersion.HTTP_1_1));
+        HttpRequestWrapper req1 = HttpRequestWrapper.wrap(
+                new BasicHttpRequest("GET", "/", HttpVersion.HTTP_1_1));
         req1.setHeader("Accept-Encoding", "gzip");
 
         HttpResponse resp1 = HttpTestUtils.make200Response();
@@ -1811,7 +2012,8 @@ public class TestProtocolRequirements ex
         resp1.setHeader("Vary", "Accept-Encoding");
         resp1.setEntity(HttpTestUtils.makeBody(entityLength));
 
-        HttpRequest req2 = HttpRequestWrapper.wrap(new BasicHttpRequest("GET", "/", HttpVersion.HTTP_1_1));
+        HttpRequestWrapper req2 = HttpRequestWrapper.wrap(
+                new BasicHttpRequest("GET", "/", HttpVersion.HTTP_1_1));
         req1.setHeader("Accept-Encoding", "gzip");
         req1.setHeader("Cache-Control", "no-cache");
 
@@ -1822,21 +2024,30 @@ public class TestProtocolRequirements ex
         resp2.setHeader("Vary", "Accept-Encoding");
         resp2.setEntity(HttpTestUtils.makeBody(entityLength));
 
-        HttpRequest req3 = HttpRequestWrapper.wrap(new BasicHttpRequest("GET", "/", HttpVersion.HTTP_1_1));
+        HttpRequestWrapper req3 = HttpRequestWrapper.wrap(
+                new BasicHttpRequest("GET", "/", HttpVersion.HTTP_1_1));
         req3.setHeader("Accept-Encoding", "gzip");
         req3.setHeader("If-None-Match", "\"v2\"");
 
         EasyMock.expect(
-                mockBackend.execute(EasyMock.isA(HttpHost.class), EasyMock.isA(HttpRequest.class),
-                        (HttpContext) EasyMock.isNull())).andReturn(resp1);
-        EasyMock.expect(
-                mockBackend.execute(EasyMock.isA(HttpHost.class), EasyMock.isA(HttpRequest.class),
-                        (HttpContext) EasyMock.isNull())).andReturn(resp2).times(1, 2);
-        replayMocks();
-
-        impl.execute(host, req1);
-        impl.execute(host, req2);
-        HttpResponse result = impl.execute(host, req3);
+                mockBackend.execute(
+                        EasyMock.isA(HttpRoute.class),
+                        EasyMock.isA(HttpRequestWrapper.class),
+                        EasyMock.isA(HttpClientContext.class),
+                        EasyMock.<HttpExecutionAware>isNull())).andReturn(
+                                Proxies.enhanceResponse(resp1));
+        EasyMock.expect(
+                mockBackend.execute(
+                        EasyMock.isA(HttpRoute.class),
+                        EasyMock.isA(HttpRequestWrapper.class),
+                        EasyMock.isA(HttpClientContext.class),
+                        EasyMock.<HttpExecutionAware>isNull())).andReturn(
+                                Proxies.enhanceResponse(resp2)).times(1, 2);
+        replayMocks();
+
+        impl.execute(route, req1);
+        impl.execute(route, req2);
+        HttpResponse result = impl.execute(route, req3);
 
         verifyMocks();
 
@@ -1861,7 +2072,8 @@ public class TestProtocolRequirements ex
         Date now = new Date();
         Date oneHourAgo = new Date(now.getTime() - 3600 * 1000L);
 
-        HttpRequest req1 = HttpRequestWrapper.wrap(new BasicHttpRequest("GET", "/", HttpVersion.HTTP_1_1));
+        HttpRequestWrapper req1 = HttpRequestWrapper.wrap(
+                new BasicHttpRequest("GET", "/", HttpVersion.HTTP_1_1));
 
         HttpResponse resp1 = HttpTestUtils.make200Response();
         resp1.setHeader("ETag", "W/\"v1\"");
@@ -1874,16 +2086,21 @@ public class TestProtocolRequirements ex
         resp1.setHeader("Last-Modified", DateUtils.formatDate(oneHourAgo));
         resp1.setHeader("Cache-Control", "max-age=7200");
 
-        HttpRequest req2 = HttpRequestWrapper.wrap(new BasicHttpRequest("GET", "/", HttpVersion.HTTP_1_1));
+        HttpRequestWrapper req2 = HttpRequestWrapper.wrap(
+                new BasicHttpRequest("GET", "/", HttpVersion.HTTP_1_1));
         req2.setHeader("If-None-Match", "W/\"v1\"");
 
         EasyMock.expect(
-                mockBackend.execute(EasyMock.isA(HttpHost.class), EasyMock.isA(HttpRequest.class),
-                        (HttpContext) EasyMock.isNull())).andReturn(resp1).times(1, 2);
+                mockBackend.execute(
+                        EasyMock.isA(HttpRoute.class),
+                        EasyMock.isA(HttpRequestWrapper.class),
+                        EasyMock.isA(HttpClientContext.class),
+                        EasyMock.<HttpExecutionAware>isNull())).andReturn(
+                                Proxies.enhanceResponse(resp1)).times(1, 2);
         replayMocks();
 
-        impl.execute(host, req1);
-        HttpResponse result = impl.execute(host, req2);
+        impl.execute(route, req1);
+        HttpResponse result = impl.execute(route, req2);
 
         verifyMocks();
 
@@ -1911,13 +2128,15 @@ public class TestProtocolRequirements ex
         Date now = new Date();
 
         // load cache with cacheable entry
-        HttpRequest req1 = HttpRequestWrapper.wrap(new BasicHttpRequest("GET", "/", HttpVersion.HTTP_1_1));
+        HttpRequestWrapper req1 = HttpRequestWrapper.wrap(
+                new BasicHttpRequest("GET", "/", HttpVersion.HTTP_1_1));
         HttpResponse resp1 = HttpTestUtils.make200Response();
         resp1.setHeader("ETag", "\"etag1\"");
         resp1.setHeader("Cache-Control", "max-age=3600");
 
         // force a revalidation
-        HttpRequest req2 = HttpRequestWrapper.wrap(new BasicHttpRequest("GET", "/", HttpVersion.HTTP_1_1));
+        HttpRequestWrapper req2 = HttpRequestWrapper.wrap(
+                new BasicHttpRequest("GET", "/", HttpVersion.HTTP_1_1));
         req2.setHeader("Cache-Control", "max-age=0,max-stale=0");
 
         // updated ETag provided to a conditional revalidation
@@ -1928,31 +2147,45 @@ public class TestProtocolRequirements ex
         resp2.setHeader("ETag", "\"etag2\"");
 
         // conditional validation uses If-None-Match
-        HttpRequest conditionalValidation = HttpRequestWrapper.wrap(new BasicHttpRequest("GET", "/", HttpVersion.HTTP_1_1));
+        HttpRequestWrapper conditionalValidation = HttpRequestWrapper.wrap(
+                new BasicHttpRequest("GET", "/", HttpVersion.HTTP_1_1));
         conditionalValidation.setHeader("If-None-Match", "\"etag1\"");
 
         // unconditional validation doesn't use If-None-Match
-        HttpRequest unconditionalValidation = HttpRequestWrapper.wrap(new BasicHttpRequest("GET", "/", HttpVersion.HTTP_1_1));
+        HttpRequestWrapper unconditionalValidation = HttpRequestWrapper.wrap(
+                new BasicHttpRequest("GET", "/", HttpVersion.HTTP_1_1));
         // new response to unconditional validation provides new body
         HttpResponse resp3 = HttpTestUtils.make200Response();
         resp1.setHeader("ETag", "\"etag2\"");
         resp1.setHeader("Cache-Control", "max-age=3600");
 
         EasyMock.expect(
-                mockBackend.execute(EasyMock.isA(HttpHost.class), EasyMock.isA(HttpRequest.class),
-                        (HttpContext) EasyMock.isNull())).andReturn(resp1);
+                mockBackend.execute(
+                        EasyMock.isA(HttpRoute.class),
+                        EasyMock.isA(HttpRequestWrapper.class),
+                        EasyMock.isA(HttpClientContext.class),
+                        EasyMock.<HttpExecutionAware>isNull())).andReturn(
+                                Proxies.enhanceResponse(resp1));
         // this next one will happen once if the cache tries to
         // conditionally validate, zero if it goes full revalidation
         EasyMock.expect(
-                mockBackend.execute(EasyMock.eq(host), eqRequest(conditionalValidation),
-                        (HttpContext) EasyMock.isNull())).andReturn(resp2).times(0, 1);
-        EasyMock.expect(
-                mockBackend.execute(EasyMock.eq(host), eqRequest(unconditionalValidation),
-                        (HttpContext) EasyMock.isNull())).andReturn(resp3);
+                mockBackend.execute(
+                        EasyMock.eq(route),
+                        eqRequest(conditionalValidation),
+                        EasyMock.isA(HttpClientContext.class),
+                        EasyMock.<HttpExecutionAware>isNull())).andReturn(
+                                Proxies.enhanceResponse(resp2)).times(0, 1);
+        EasyMock.expect(
+                mockBackend.execute(
+                        EasyMock.eq(route),
+                        eqRequest(unconditionalValidation),
+                        EasyMock.isA(HttpClientContext.class),
+                        EasyMock.<HttpExecutionAware>isNull())).andReturn(
+                                Proxies.enhanceResponse(resp3));
         replayMocks();
 
-        impl.execute(host, req1);
-        impl.execute(host, req2);
+        impl.execute(route, req1);
+        impl.execute(route, req2);
 
         verifyMocks();
     }
@@ -1970,22 +2203,27 @@ public class TestProtocolRequirements ex
         Date now = new Date();
         Date inFiveSeconds = new Date(now.getTime() + 5000L);
 
-        HttpRequest initialRequest = HttpRequestWrapper.wrap(new BasicHttpRequest("GET", "/", HttpVersion.HTTP_1_1));
+        HttpRequestWrapper initialRequest = HttpRequestWrapper.wrap(
+                new BasicHttpRequest("GET", "/", HttpVersion.HTTP_1_1));
 
         HttpResponse cachedResponse = HttpTestUtils.make200Response();
         cachedResponse.setHeader("Cache-Control", "max-age=3600");
         cachedResponse.setHeader("ETag", "\"etag\"");
 
-        HttpRequest secondRequest = HttpRequestWrapper.wrap(new BasicHttpRequest("GET", "/", HttpVersion.HTTP_1_1));
+        HttpRequestWrapper secondRequest = HttpRequestWrapper.wrap(
+                new BasicHttpRequest("GET", "/", HttpVersion.HTTP_1_1));
         secondRequest.setHeader("Cache-Control", "max-age=0,max-stale=0");
 
-        HttpRequest conditionalValidationRequest = HttpRequestWrapper.wrap(new BasicHttpRequest("GET", "/", HttpVersion.HTTP_1_1));
+        HttpRequestWrapper conditionalValidationRequest = HttpRequestWrapper.wrap(
+                new BasicHttpRequest("GET", "/", HttpVersion.HTTP_1_1));
         conditionalValidationRequest.setHeader("If-None-Match", "\"etag\"");
 
-        HttpRequest unconditionalValidationRequest = HttpRequestWrapper.wrap(new BasicHttpRequest("GET", "/", HttpVersion.HTTP_1_1));
+        HttpRequestWrapper unconditionalValidationRequest = HttpRequestWrapper.wrap(
+                new BasicHttpRequest("GET", "/", HttpVersion.HTTP_1_1));
 
         // to be used if the cache generates a conditional validation
-        HttpResponse conditionalResponse = new BasicHttpResponse(HttpVersion.HTTP_1_1, HttpStatus.SC_NOT_MODIFIED, "Not Modified");
+        HttpResponse conditionalResponse = new BasicHttpResponse(
+                HttpVersion.HTTP_1_1, HttpStatus.SC_NOT_MODIFIED, "Not Modified");
         conditionalResponse.setHeader("Date", DateUtils.formatDate(inFiveSeconds));
         conditionalResponse.setHeader("Server", "MockUtils/1.0");
         conditionalResponse.setHeader("ETag", "\"etag\"");
@@ -1996,25 +2234,35 @@ public class TestProtocolRequirements ex
         unconditionalResponse.setHeader("Date", DateUtils.formatDate(inFiveSeconds));
         unconditionalResponse.setHeader("ETag", "\"etag\"");
 
-        Capture<HttpRequest> cap1 = new Capture<HttpRequest>();
-        Capture<HttpRequest> cap2 = new Capture<HttpRequest>();
+        Capture<HttpRequestWrapper> cap1 = new Capture<HttpRequestWrapper>();
+        Capture<HttpRequestWrapper> cap2 = new Capture<HttpRequestWrapper>();
 
         EasyMock.expect(
-                mockBackend.execute(EasyMock.isA(HttpHost.class), EasyMock.isA(HttpRequest.class),
-                        (HttpContext) EasyMock.isNull())).andReturn(cachedResponse);
-        EasyMock.expect(
-                mockBackend.execute(EasyMock.eq(host), EasyMock.and(
-                        eqRequest(conditionalValidationRequest), EasyMock.capture(cap1)),
-                        (HttpContext) EasyMock.isNull())).andReturn(conditionalResponse).times(0, 1);
-        EasyMock.expect(
-                mockBackend.execute(EasyMock.eq(host), EasyMock.and(
-                        eqRequest(unconditionalValidationRequest), EasyMock.capture(cap2)),
-                        (HttpContext) EasyMock.isNull())).andReturn(unconditionalResponse).times(0, 1);
+                mockBackend.execute(
+                        EasyMock.isA(HttpRoute.class),
+                        EasyMock.isA(HttpRequestWrapper.class),
+                        EasyMock.isA(HttpClientContext.class),
+                        EasyMock.<HttpExecutionAware>isNull())).andReturn(
+                                Proxies.enhanceResponse(cachedResponse));
+        EasyMock.expect(
+                mockBackend.execute(
+                        EasyMock.eq(route),
+                        EasyMock.and(eqRequest(conditionalValidationRequest), EasyMock.capture(cap1)),
+                        EasyMock.isA(HttpClientContext.class),
+                        EasyMock.<HttpExecutionAware>isNull())).andReturn(
+                                Proxies.enhanceResponse(conditionalResponse)).times(0, 1);
+        EasyMock.expect(
+                mockBackend.execute(
+                        EasyMock.eq(route),
+                        EasyMock.and(eqRequest(unconditionalValidationRequest), EasyMock.capture(cap2)),
+                        EasyMock.isA(HttpClientContext.class),
+                        EasyMock.<HttpExecutionAware>isNull())).andReturn(
+                                Proxies.enhanceResponse(unconditionalResponse)).times(0, 1);
 
         replayMocks();
 
-        impl.execute(host, initialRequest);
-        HttpResponse result = impl.execute(host, secondRequest);
+        impl.execute(route, initialRequest);
+        HttpResponse result = impl.execute(route, secondRequest);
 
         verifyMocks();
 
@@ -2037,15 +2285,19 @@ public class TestProtocolRequirements ex
      */
     @Test
     public void testMustIncludeWWWAuthenticateHeaderOnAnOrigin401Response() throws Exception {
-        originResponse = new BasicHttpResponse(HttpVersion.HTTP_1_1, 401, "Unauthorized");
+        originResponse = Proxies.enhanceResponse(
+                new BasicHttpResponse(HttpVersion.HTTP_1_1, 401, "Unauthorized"));
         originResponse.setHeader("WWW-Authenticate", "x-scheme x-param");
 
         EasyMock.expect(
-                mockBackend.execute(EasyMock.isA(HttpHost.class), EasyMock.isA(HttpRequest.class),
-                        (HttpContext) EasyMock.isNull())).andReturn(originResponse);
+                mockBackend.execute(
+                        EasyMock.isA(HttpRoute.class),
+                        EasyMock.isA(HttpRequestWrapper.class),
+                        EasyMock.isA(HttpClientContext.class),
+                        EasyMock.<HttpExecutionAware>isNull())).andReturn(originResponse);
         replayMocks();
 
-        HttpResponse result = impl.execute(host, request);
+        HttpResponse result = impl.execute(route, request);
         if (result.getStatusLine().getStatusCode() == 401) {
             Assert.assertNotNull(result.getFirstHeader("WWW-Authenticate"));
         }
@@ -2061,14 +2313,15 @@ public class TestProtocolRequirements ex
      */
     @Test
     public void testMustIncludeAllowHeaderFromAnOrigin405Response() throws Exception {
-        originResponse = new BasicHttpResponse(HttpVersion.HTTP_1_1, 405, "Method Not Allowed");
+        originResponse = Proxies.enhanceResponse(
+                new BasicHttpResponse(HttpVersion.HTTP_1_1, 405, "Method Not Allowed"));
         originResponse.setHeader("Allow", "GET, HEAD");
 
         backendExpectsAnyRequest().andReturn(originResponse);
 
         replayMocks();
 
-        HttpResponse result = impl.execute(host, request);
+        HttpResponse result = impl.execute(route, request);
         if (result.getStatusLine().getStatusCode() == 405) {
             Assert.assertNotNull(result.getFirstHeader("Allow"));
         }
@@ -2085,15 +2338,19 @@ public class TestProtocolRequirements ex
      */
     @Test
     public void testMustIncludeProxyAuthenticateHeaderFromAnOrigin407Response() throws Exception {
-        originResponse = new BasicHttpResponse(HttpVersion.HTTP_1_1, 407, "Proxy Authentication Required");
+        originResponse = Proxies.enhanceResponse(
+                new BasicHttpResponse(HttpVersion.HTTP_1_1, 407, "Proxy Authentication Required"));
         originResponse.setHeader("Proxy-Authenticate", "x-scheme x-param");
 
         EasyMock.expect(
-                mockBackend.execute(EasyMock.isA(HttpHost.class), EasyMock.isA(HttpRequest.class),
-                        (HttpContext) EasyMock.isNull())).andReturn(originResponse);
+                mockBackend.execute(
+                        EasyMock.isA(HttpRoute.class),
+                        EasyMock.isA(HttpRequestWrapper.class),
+                        EasyMock.isA(HttpClientContext.class),
+                        EasyMock.<HttpExecutionAware>isNull())).andReturn(originResponse);
         replayMocks();
 
-        HttpResponse result = impl.execute(host, request);
+        HttpResponse result = impl.execute(route, request);
         if (result.getStatusLine().getStatusCode() == 407) {
             Assert.assertNotNull(result.getFirstHeader("Proxy-Authenticate"));
         }
@@ -2109,14 +2366,18 @@ public class TestProtocolRequirements ex
      */
     @Test
     public void testMustNotAddMultipartByteRangeContentTypeTo416Response() throws Exception {
-        originResponse = new BasicHttpResponse(HttpVersion.HTTP_1_1, 416, "Requested Range Not Satisfiable");

[... 2769 lines stripped ...]