hc-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From j...@apache.org
Subject svn commit: r1301090 - in /httpcomponents/httpclient/trunk: ./ httpclient/src/main/java/org/apache/http/client/protocol/ httpclient/src/main/java/org/apache/http/impl/client/ httpclient/src/test/java/org/apache/http/impl/client/
Date Thu, 15 Mar 2012 17:02:08 GMT
Author: jonm
Date: Thu Mar 15 17:02:07 2012
New Revision: 1301090

URL: http://svn.apache.org/viewvc?rev=1301090&view=rev
Log:
HTTPCLIENT-1164: Implemented a new CompressionDecorator aimed at replacing
the ContentEncodingHttpClient. This reuses the same request/response
interceptors with some minor additions to make the resulting response
semantically consistent (i.e. if a response is uncompressed, we mark the
entity as having an unknown length and remove the Content-Length header
before passing the response upstream). This allows the CompressionDecorator
and CachingHttpClient to be wired around a DefaultHttpClient in either order
and still get cache hits, depending on whether you want to cache compressed
or uncompressed bodies.

Minor change to ResponseContentEncoding to set a context variable that the
uncompression was applied. Only other change was to deprecate the
ContentEncodingHttpClient.

Added:
    httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/impl/client/CompressionDecorator.java
  (with props)
    httpcomponents/httpclient/trunk/httpclient/src/test/java/org/apache/http/impl/client/DummyHttpClient.java
  (with props)
    httpcomponents/httpclient/trunk/httpclient/src/test/java/org/apache/http/impl/client/TestCompressionDecorator.java
  (with props)
Modified:
    httpcomponents/httpclient/trunk/RELEASE_NOTES.txt
    httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/client/protocol/ResponseContentEncoding.java
    httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/impl/client/ContentEncodingHttpClient.java

Modified: httpcomponents/httpclient/trunk/RELEASE_NOTES.txt
URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/RELEASE_NOTES.txt?rev=1301090&r1=1301089&r2=1301090&view=diff
==============================================================================
--- httpcomponents/httpclient/trunk/RELEASE_NOTES.txt (original)
+++ httpcomponents/httpclient/trunk/RELEASE_NOTES.txt Thu Mar 15 17:02:07 2012
@@ -21,6 +21,8 @@ notable enhancements in HttpClient:
 
 Changelog
 -------------------
+* [HTTPCLIENT-1164] Compressed entities are not being cached properly.
+  Contributed by Jon Moore <jonm at apache dot org>.
 
 * [HTTPCLIENT-1154] MemcachedHttpCacheStorage should allow client to
   specify custom prefix string for keys.

Modified: httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/client/protocol/ResponseContentEncoding.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/client/protocol/ResponseContentEncoding.java?rev=1301090&r1=1301089&r2=1301090&view=diff
==============================================================================
--- httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/client/protocol/ResponseContentEncoding.java
(original)
+++ httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/client/protocol/ResponseContentEncoding.java
Thu Mar 15 17:02:07 2012
@@ -52,6 +52,8 @@ import org.apache.http.protocol.HttpCont
 @Immutable
 public class ResponseContentEncoding implements HttpResponseInterceptor {
 
+    public static final String UNCOMPRESSED = "http.client.response.uncompressed"; 
+    
     /**
      * Handles the following {@code Content-Encoding}s by
      * using the appropriate decompressor to wrap the response Entity:
@@ -80,9 +82,11 @@ public class ResponseContentEncoding imp
                     String codecname = codec.getName().toLowerCase(Locale.US);
                     if ("gzip".equals(codecname) || "x-gzip".equals(codecname)) {
                         response.setEntity(new GzipDecompressingEntity(response.getEntity()));
+                        if (context != null) context.setAttribute(UNCOMPRESSED, true);  
                         return;
                     } else if ("deflate".equals(codecname)) {
                         response.setEntity(new DeflateDecompressingEntity(response.getEntity()));
+                        if (context != null) context.setAttribute(UNCOMPRESSED, true);
                         return;
                     } else if ("identity".equals(codecname)) {
 

Added: httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/impl/client/CompressionDecorator.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/impl/client/CompressionDecorator.java?rev=1301090&view=auto
==============================================================================
--- httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/impl/client/CompressionDecorator.java
(added)
+++ httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/impl/client/CompressionDecorator.java
Thu Mar 15 17:02:07 2012
@@ -0,0 +1,168 @@
+/*
+ * ====================================================================
+ * 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.impl.client;
+
+import java.io.IOException;
+import java.net.URI;
+
+import org.apache.http.HttpEntity;
+import org.apache.http.HttpException;
+import org.apache.http.HttpHost;
+import org.apache.http.HttpRequest;
+import org.apache.http.HttpRequestInterceptor;
+import org.apache.http.HttpResponse;
+import org.apache.http.HttpResponseInterceptor;
+import org.apache.http.client.ClientProtocolException;
+import org.apache.http.client.HttpClient;
+import org.apache.http.client.ResponseHandler;
+import org.apache.http.client.methods.HttpUriRequest;
+import org.apache.http.client.protocol.RequestAcceptEncoding;
+import org.apache.http.client.protocol.ResponseContentEncoding;
+import org.apache.http.conn.ClientConnectionManager;
+import org.apache.http.params.HttpParams;
+import org.apache.http.protocol.BasicHttpContext;
+import org.apache.http.protocol.HttpContext;
+import org.apache.http.util.EntityUtils;
+
+/*
+ * <p>Decorator adding support for compressed responses. This class sets
+ * the <code>Accept-Encoding</code> header on requests to indicate
+ * support for the <code>gzip</code> and <code>deflate</code>
+ * compression schemes; it then checks the <code>Content-Encoding</code>
+ * header on the response to uncompress any compressed response bodies.
+ * The {@link InputStream} of the entity will contain the uncompressed
+ * content.</p>
+ * 
+ * <p><b>N.B.</b> Any upstream clients of this class need to be aware that
+ * this effectively obscures visibility into the length of a server
+ * response body, since the <code>Content-Length</code> header will
+ * correspond to the compressed entity length received from the server,
+ * but the content length experienced by reading the response body may
+ * be different (hopefully higher!).</p>
+ * 
+ * <p>That said, this decorator is compatible with the {@link CachingHttpClient}
+ * in that the two decorators can be added in either order and still have
+ * cacheable responses be cached.</p> 
+ */
+public class CompressionDecorator implements HttpClient {
+
+    private HttpClient backend;
+    private HttpRequestInterceptor acceptEncodingInterceptor;
+    private HttpResponseInterceptor contentEncodingInterceptor;
+    
+    /*
+     * Constructs a decorator to ask for and handle compressed
+     * entities on the fly.
+     * @param backend the {@link HttpClient} to use for actually
+     *   issuing requests
+     */
+    public CompressionDecorator(HttpClient backend) {
+        this(backend, new RequestAcceptEncoding(), new ResponseContentEncoding());
+    }
+    
+    CompressionDecorator(HttpClient backend, HttpRequestInterceptor requestInterceptor, HttpResponseInterceptor
responseInterceptor) {
+        this.backend = backend;
+        this.acceptEncodingInterceptor = requestInterceptor;
+        this.contentEncodingInterceptor = responseInterceptor;
+    }
+
+    public HttpParams getParams() {
+        return backend.getParams();
+    }
+
+    public ClientConnectionManager getConnectionManager() {
+        return backend.getConnectionManager();
+    }
+
+    public HttpResponse execute(HttpUriRequest request) throws IOException,
+            ClientProtocolException {
+        return execute(getHttpHost(request), request, (HttpContext)null);
+    }
+
+    HttpHost getHttpHost(HttpUriRequest request) {
+        URI uri = request.getURI();
+        return new HttpHost(uri.getAuthority());
+    }
+
+    public HttpResponse execute(HttpUriRequest request, HttpContext context)
+            throws IOException, ClientProtocolException {
+        return execute(getHttpHost(request), request, context);
+    }
+
+    public HttpResponse execute(HttpHost target, HttpRequest request)
+            throws IOException, ClientProtocolException {
+        return execute(target, request, (HttpContext)null);
+    }
+
+    public HttpResponse execute(HttpHost target, HttpRequest request,
+            HttpContext context) throws IOException, ClientProtocolException {
+        try {
+            if (context == null) context = new BasicHttpContext();
+            HttpRequest wrapped = new RequestWrapper(request);
+            acceptEncodingInterceptor.process(wrapped, context);
+            HttpResponse response = backend.execute(target, wrapped, context);
+            contentEncodingInterceptor.process(response, context);
+            if (Boolean.TRUE.equals(context.getAttribute(ResponseContentEncoding.UNCOMPRESSED)))
{
+                response.removeHeaders("Content-Length");
+                response.removeHeaders("Content-Encoding");
+            }
+            return response;
+        } catch (HttpException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    public <T> T execute(HttpUriRequest request,
+            ResponseHandler<? extends T> responseHandler) throws IOException,
+            ClientProtocolException {
+        return execute(getHttpHost(request), request, responseHandler);
+    }
+
+    public <T> T execute(HttpUriRequest request,
+            ResponseHandler<? extends T> responseHandler, HttpContext context)
+            throws IOException, ClientProtocolException {
+        return execute(getHttpHost(request), request, responseHandler, context);
+    }
+
+    public <T> T execute(HttpHost target, HttpRequest request,
+            ResponseHandler<? extends T> responseHandler) throws IOException,
+            ClientProtocolException {
+        return execute(target, request, responseHandler, null);
+    }
+
+    public <T> T execute(HttpHost target, HttpRequest request,
+            ResponseHandler<? extends T> responseHandler, HttpContext context)
+            throws IOException, ClientProtocolException {
+        HttpResponse response = execute(target, request, context);
+        try {
+            return responseHandler.handleResponse(response);
+        } finally {
+            HttpEntity entity = response.getEntity();
+            if (entity != null) EntityUtils.consume(entity);
+        }
+    }
+
+}

Propchange: httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/impl/client/CompressionDecorator.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/impl/client/ContentEncodingHttpClient.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/impl/client/ContentEncodingHttpClient.java?rev=1301090&r1=1301089&r2=1301090&view=diff
==============================================================================
--- httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/impl/client/ContentEncodingHttpClient.java
(original)
+++ httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/impl/client/ContentEncodingHttpClient.java
Thu Mar 15 17:02:07 2012
@@ -36,9 +36,18 @@ import org.apache.http.protocol.BasicHtt
 /**
  * {@link DefaultHttpClient} sub-class which includes a {@link RequestAcceptEncoding}
  * for the request and response.
+ * 
+ * <b>Deprecation note:</b> due to the way this class modifies a response body
+ * without changing the response headers to reflect the entity changes, it cannot
+ * be used as the &quot;backend&quot; for a {@link CachingHttpClient} and still
+ * have uncompressed responses be cached. Users are encouraged to use the
+ * {@link CompressionDecorator} instead of this class, which can be wired in
+ * either before or after caching, depending on whether you want to cache
+ * responses in compressed or uncompressed form.
  *
  * @since 4.1
  */
+@Deprecated
 @ThreadSafe // since DefaultHttpClient is
 public class ContentEncodingHttpClient extends DefaultHttpClient {
 

Added: httpcomponents/httpclient/trunk/httpclient/src/test/java/org/apache/http/impl/client/DummyHttpClient.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/httpclient/src/test/java/org/apache/http/impl/client/DummyHttpClient.java?rev=1301090&view=auto
==============================================================================
--- httpcomponents/httpclient/trunk/httpclient/src/test/java/org/apache/http/impl/client/DummyHttpClient.java
(added)
+++ httpcomponents/httpclient/trunk/httpclient/src/test/java/org/apache/http/impl/client/DummyHttpClient.java
Thu Mar 15 17:02:07 2012
@@ -0,0 +1,105 @@
+package org.apache.http.impl.client;
+
+import java.io.IOException;
+
+import org.apache.http.HttpHost;
+import org.apache.http.HttpRequest;
+import org.apache.http.HttpResponse;
+import org.apache.http.HttpStatus;
+import org.apache.http.ProtocolVersion;
+import org.apache.http.client.ClientProtocolException;
+import org.apache.http.client.HttpClient;
+import org.apache.http.client.ResponseHandler;
+import org.apache.http.client.methods.HttpUriRequest;
+import org.apache.http.conn.ClientConnectionManager;
+import org.apache.http.impl.conn.SingleClientConnManager;
+import org.apache.http.message.BasicHttpResponse;
+import org.apache.http.params.BasicHttpParams;
+import org.apache.http.params.HttpParams;
+import org.apache.http.protocol.HttpContext;
+
+@SuppressWarnings("deprecation")
+public class DummyHttpClient implements HttpClient {
+
+    private HttpParams params = new BasicHttpParams();
+    private ClientConnectionManager connManager = new SingleClientConnManager();
+    private HttpRequest request;
+    private HttpResponse response = new BasicHttpResponse(new ProtocolVersion("HTTP",1,1),
HttpStatus.SC_OK, "OK");
+    
+    public void setParams(HttpParams params) {
+        this.params = params;
+    }
+    
+    public HttpParams getParams() {
+        return params;
+    }
+
+    public ClientConnectionManager getConnectionManager() {
+        return connManager;
+    }
+    
+    public void setConnectionManager(ClientConnectionManager ccm) {
+        connManager = ccm;
+    }
+    
+    public void setResponse(HttpResponse resp) {
+        response = resp;
+    }
+    
+    public HttpRequest getCapturedRequest() {
+        return request;
+    }
+
+    public HttpResponse execute(HttpUriRequest request) throws IOException,
+            ClientProtocolException {
+        this.request = request;
+        return response;
+    }
+
+    public HttpResponse execute(HttpUriRequest request, HttpContext context)
+            throws IOException, ClientProtocolException {
+        this.request = request;
+        return response;
+    }
+
+    public HttpResponse execute(HttpHost target, HttpRequest request)
+            throws IOException, ClientProtocolException {
+        this.request = request;
+        return response;
+    }
+
+    public HttpResponse execute(HttpHost target, HttpRequest request,
+            HttpContext context) throws IOException, ClientProtocolException {
+        this.request = request;
+        return response;
+    }
+
+    public <T> T execute(HttpUriRequest request,
+            ResponseHandler<? extends T> responseHandler) throws IOException,
+            ClientProtocolException {
+        this.request = request;
+        return responseHandler.handleResponse(response);
+    }
+
+    public <T> T execute(HttpUriRequest request,
+            ResponseHandler<? extends T> responseHandler, HttpContext context)
+            throws IOException, ClientProtocolException {
+        this.request = request;
+        return responseHandler.handleResponse(response);
+    }
+
+    public <T> T execute(HttpHost target, HttpRequest request,
+            ResponseHandler<? extends T> responseHandler) throws IOException,
+            ClientProtocolException {
+        this.request = request;
+        return responseHandler.handleResponse(response);
+    }
+
+    public <T> T execute(HttpHost target, HttpRequest request,
+            ResponseHandler<? extends T> responseHandler, HttpContext context)
+            throws IOException, ClientProtocolException {
+        this.request = request;
+        return responseHandler.handleResponse(response);
+    }
+
+}

Propchange: httpcomponents/httpclient/trunk/httpclient/src/test/java/org/apache/http/impl/client/DummyHttpClient.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: httpcomponents/httpclient/trunk/httpclient/src/test/java/org/apache/http/impl/client/TestCompressionDecorator.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/httpclient/src/test/java/org/apache/http/impl/client/TestCompressionDecorator.java?rev=1301090&view=auto
==============================================================================
--- httpcomponents/httpclient/trunk/httpclient/src/test/java/org/apache/http/impl/client/TestCompressionDecorator.java
(added)
+++ httpcomponents/httpclient/trunk/httpclient/src/test/java/org/apache/http/impl/client/TestCompressionDecorator.java
Thu Mar 15 17:02:07 2012
@@ -0,0 +1,330 @@
+/*
+ * ====================================================================
+ * 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.impl.client;
+
+import static org.junit.Assert.*;
+import static org.mockito.Mockito.*;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.zip.GZIPOutputStream;
+
+import org.apache.http.Header;
+import org.apache.http.HeaderElement;
+import org.apache.http.HttpEntity;
+import org.apache.http.HttpHost;
+import org.apache.http.HttpRequest;
+import org.apache.http.HttpResponse;
+import org.apache.http.HttpStatus;
+import org.apache.http.HttpVersion;
+import org.apache.http.client.HttpClient;
+import org.apache.http.client.ResponseHandler;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.client.methods.HttpUriRequest;
+import org.apache.http.conn.ClientConnectionManager;
+import org.apache.http.entity.ByteArrayEntity;
+import org.apache.http.message.BasicHttpResponse;
+import org.apache.http.params.BasicHttpParams;
+import org.apache.http.params.HttpParams;
+import org.apache.http.protocol.BasicHttpContext;
+import org.apache.http.protocol.HttpContext;
+import org.apache.http.util.EntityUtils;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.runners.MockitoJUnitRunner;
+
+@RunWith(MockitoJUnitRunner.class)
+public class TestCompressionDecorator {
+    
+    private DummyHttpClient backend;
+    @Mock private ClientConnectionManager mockConnManager;
+    @Mock private ResponseHandler<Object> mockHandler;
+    private CompressionDecorator impl;
+    private HttpUriRequest request;
+    private HttpContext ctx;
+    private HttpHost host;
+    @Mock private HttpResponse mockResponse;
+    @Mock private HttpEntity mockEntity;
+    private Object handled;
+    
+    @Before
+    public void canCreate() {
+        handled = new Object();
+        backend = new DummyHttpClient();
+        impl = new CompressionDecorator(backend);
+        request = new HttpGet("http://localhost:8080");
+        ctx = new BasicHttpContext();
+        host = new HttpHost("www.example.com");
+    }
+    
+    @Test
+    public void isAnHttpClient() {
+        assertTrue(impl instanceof HttpClient);
+    }
+    
+    @Test
+    public void usesParamsFromBackend() {
+        HttpParams params = new BasicHttpParams();
+        backend.setParams(params);
+        assertSame(params, impl.getParams());
+    }
+    
+    @Test
+    public void extractsHostNameFromUriRequest() {
+        assertEquals(new HttpHost("www.example.com"), 
+                impl.getHttpHost(new HttpGet("http://www.example.com/")));
+    }
+    
+    @Test
+    public void extractsHostNameAndPortFromUriRequest() {
+        assertEquals(new HttpHost("www.example.com:8080"), 
+                impl.getHttpHost(new HttpGet("http://www.example.com:8080/")));
+    }
+
+    @Test
+    public void extractsIPAddressFromUriRequest() {
+        assertEquals(new HttpHost("10.0.0.1"), 
+                impl.getHttpHost(new HttpGet("http://10.0.0.1/")));
+    }
+
+    @Test
+    public void extractsIPAddressAndPortFromUriRequest() {
+        assertEquals(new HttpHost("10.0.0.1:8080"), 
+                impl.getHttpHost(new HttpGet("http://10.0.0.1:8080/")));
+    }
+
+    @Test
+    public void extractsLocalhostFromUriRequest() {
+        assertEquals(new HttpHost("localhost"), 
+                impl.getHttpHost(new HttpGet("http://localhost/")));
+    }
+
+    @Test
+    public void extractsLocalhostAndPortFromUriRequest() {
+        assertEquals(new HttpHost("localhost:8080"), 
+                impl.getHttpHost(new HttpGet("http://localhost:8080/")));
+    }
+    
+    @Test
+    public void usesConnectionManagerFromBackend() {
+        backend.setConnectionManager(mockConnManager);
+        assertSame(mockConnManager, impl.getConnectionManager());
+    }
+    
+    private void assertAcceptEncodingGzipAndDeflateWereAddedToRequest(HttpRequest captured)
{
+        boolean foundGzip = false;
+        boolean foundDeflate = false;
+        for(Header h : captured.getHeaders("Accept-Encoding")) {
+            for(HeaderElement elt : h.getElements()) {
+                if ("gzip".equals(elt.getName())) foundGzip = true;
+                if ("deflate".equals(elt.getName())) foundDeflate = true;
+            }
+        }
+        assertTrue(foundGzip);
+        assertTrue(foundDeflate);
+    }
+    
+    @Test
+    public void addsAcceptEncodingHeaderToHttpUriRequest() throws Exception {
+        impl.execute(request);
+        assertAcceptEncodingGzipAndDeflateWereAddedToRequest(backend.getCapturedRequest());
+    }
+
+    @Test
+    public void addsAcceptEncodingHeaderToHttpUriRequestWithContext() throws Exception {
+        impl.execute(request, ctx);
+        assertAcceptEncodingGzipAndDeflateWereAddedToRequest(backend.getCapturedRequest());
+    }
+    
+    @Test
+    public void addsAcceptEncodingHeaderToHostAndHttpRequest() throws Exception {
+        impl.execute(host, request);
+        assertAcceptEncodingGzipAndDeflateWereAddedToRequest(backend.getCapturedRequest());
+    }
+    
+    @Test
+    public void addsAcceptEncodingHeaderToHostAndHttpRequestWithContext() throws Exception
{
+        impl.execute(host, request, ctx);
+        assertAcceptEncodingGzipAndDeflateWereAddedToRequest(backend.getCapturedRequest());
+    }
+    
+    @Test
+    public void addsAcceptEncodingHeaderToUriRequestWithHandler() throws Exception {
+        when(mockHandler.handleResponse(isA(HttpResponse.class))).thenReturn(new Object());
+        impl.execute(request, mockHandler);
+        assertAcceptEncodingGzipAndDeflateWereAddedToRequest(backend.getCapturedRequest());
+    }
+
+    @Test
+    public void addsAcceptEncodingHeaderToUriRequestWithHandlerAndContext() throws Exception
{
+        when(mockHandler.handleResponse(isA(HttpResponse.class))).thenReturn(new Object());
+        impl.execute(request, mockHandler, ctx);
+        assertAcceptEncodingGzipAndDeflateWereAddedToRequest(backend.getCapturedRequest());
+    }
+
+    @Test
+    public void addsAcceptEncodingHeaderToRequestWithHostAndHandler() throws Exception {
+        when(mockHandler.handleResponse(isA(HttpResponse.class))).thenReturn(new Object());
+        impl.execute(host, request, mockHandler);
+        assertAcceptEncodingGzipAndDeflateWereAddedToRequest(backend.getCapturedRequest());
+    }
+
+    @Test
+    public void addsAcceptEncodingHeaderToRequestWithHostAndContextAndHandler() throws Exception
{
+        when(mockHandler.handleResponse(isA(HttpResponse.class))).thenReturn(new Object());
+        impl.execute(host, request, mockHandler, ctx);
+        assertAcceptEncodingGzipAndDeflateWereAddedToRequest(backend.getCapturedRequest());
+    }
+
+    private void mockResponseHasNoContentEncodingHeaders() {
+        backend.setResponse(mockResponse);
+        when(mockResponse.getAllHeaders()).thenReturn(new Header[]{});
+        when(mockResponse.getHeaders("Content-Encoding")).thenReturn(new Header[]{});
+        when(mockResponse.getFirstHeader("Content-Encoding")).thenReturn(null);
+        when(mockResponse.getLastHeader("Content-Encoding")).thenReturn(null);
+        when(mockResponse.getEntity()).thenReturn(mockEntity);
+    }
+    
+    @Test
+    public void doesNotModifyResponseBodyIfNoContentEncoding() throws Exception {
+        mockResponseHasNoContentEncodingHeaders();
+        assertSame(mockResponse, impl.execute(request));
+        verify(mockResponse, never()).setEntity(any(HttpEntity.class));
+    }
+    
+    @Test
+    public void doesNotModifyResponseBodyIfNoContentEncodingWithContext() throws Exception
{
+        mockResponseHasNoContentEncodingHeaders();
+        assertSame(mockResponse, impl.execute(request, ctx));
+        verify(mockResponse, never()).setEntity(any(HttpEntity.class));
+    }
+    
+    @Test
+    public void doesNotModifyResponseBodyIfNoContentEncodingForHostRequest() throws Exception
{
+        mockResponseHasNoContentEncodingHeaders();
+        assertSame(mockResponse, impl.execute(host, request));
+        verify(mockResponse, never()).setEntity(any(HttpEntity.class));
+    }
+    
+    @Test
+    public void doesNotModifyResponseBodyIfNoContentEncodingForHostRequestWithContext() throws
Exception {
+        mockResponseHasNoContentEncodingHeaders();
+        assertSame(mockResponse, impl.execute(host, request, ctx));
+        verify(mockResponse, never()).setEntity(any(HttpEntity.class));
+    }
+    
+    @Test
+    public void doesNotModifyResponseBodyWithHandlerIfNoContentEncoding() throws Exception
{
+        mockResponseHasNoContentEncodingHeaders();
+        when(mockHandler.handleResponse(mockResponse)).thenReturn(handled);
+        assertSame(handled, impl.execute(request, mockHandler));
+        verify(mockResponse, never()).setEntity(any(HttpEntity.class));
+    }
+    
+    @Test
+    public void doesNotModifyResponseBodyWithHandlerAndContextIfNoContentEncoding() throws
Exception {
+        mockResponseHasNoContentEncodingHeaders();
+        when(mockHandler.handleResponse(mockResponse)).thenReturn(handled);
+        assertSame(handled, impl.execute(request, mockHandler, ctx));
+        verify(mockResponse, never()).setEntity(any(HttpEntity.class));
+    }
+    
+    @Test
+    public void doesNotModifyResponseBodyWithHostAndHandlerIfNoContentEncoding() throws Exception
{
+        mockResponseHasNoContentEncodingHeaders();
+        when(mockHandler.handleResponse(mockResponse)).thenReturn(handled);
+        assertSame(handled, impl.execute(host, request, mockHandler));
+        verify(mockResponse, never()).setEntity(any(HttpEntity.class));
+    }
+    
+    @Test
+    public void doesNotModifyResponseBodyWithHostAndHandlerAndContextIfNoContentEncoding()
throws Exception {
+        mockResponseHasNoContentEncodingHeaders();
+        when(mockHandler.handleResponse(mockResponse)).thenReturn(handled);
+        assertSame(handled, impl.execute(host, request, mockHandler, ctx));
+        verify(mockResponse, never()).setEntity(any(HttpEntity.class));
+    }
+
+    @Test
+    public void successfullyUncompressesContent() throws Exception {
+        final String plainText = "hello\n";
+        HttpResponse response = getGzippedResponse(plainText);
+        backend.setResponse(response);
+        
+        HttpResponse result = impl.execute(request);
+        ByteArrayOutputStream resultBuf = new ByteArrayOutputStream();
+        InputStream is = result.getEntity().getContent();
+        int b;
+        while((b = is.read()) != -1) {
+            resultBuf.write(b);
+        }
+        is.close();
+        assertEquals(plainText, new String(resultBuf.toByteArray()));
+    }
+    
+    @Test
+    public void uncompressedResponseHasUnknownLength() throws Exception {
+        final String plainText = "hello\n";
+        HttpResponse response = getGzippedResponse(plainText);
+        backend.setResponse(response);
+        
+        HttpResponse result = impl.execute(request);
+        HttpEntity entity = result.getEntity();
+        assertEquals(-1, entity.getContentLength());
+        EntityUtils.consume(entity);
+        assertNull(result.getFirstHeader("Content-Length"));
+    }
+
+    @Test
+    public void uncompressedResponseIsNotEncoded() throws Exception {
+        final String plainText = "hello\n";
+        HttpResponse response = getGzippedResponse(plainText);
+        backend.setResponse(response);
+        
+        HttpResponse result = impl.execute(request);
+        assertNull(result.getFirstHeader("Content-Encoding"));
+    }
+    
+    private HttpResponse getGzippedResponse(final String plainText)
+            throws IOException {
+        HttpResponse response = new BasicHttpResponse(HttpVersion.HTTP_1_1, HttpStatus.SC_OK,
"OK");
+        response.setHeader("Content-Encoding","gzip");
+        response.setHeader("Content-Type","text/plain");
+        ByteArrayOutputStream buf = new ByteArrayOutputStream();
+        GZIPOutputStream gos = new GZIPOutputStream(buf);
+        gos.write(plainText.getBytes());
+        gos.close();
+        ByteArrayEntity body = new ByteArrayEntity(buf.toByteArray());
+        body.setContentEncoding("gzip");
+        body.setContentType("text/plain");
+        response.setHeader("Content-Length", "" + (int)body.getContentLength());
+        response.setEntity(body);
+        return response;
+    }
+}

Propchange: httpcomponents/httpclient/trunk/httpclient/src/test/java/org/apache/http/impl/client/TestCompressionDecorator.java
------------------------------------------------------------------------------
    svn:eol-style = native



Mime
View raw message