View Javadoc

1   /*
2    * ====================================================================
3    * Licensed to the Apache Software Foundation (ASF) under one
4    * or more contributor license agreements.  See the NOTICE file
5    * distributed with this work for additional information
6    * regarding copyright ownership.  The ASF licenses this file
7    * to you under the Apache License, Version 2.0 (the
8    * "License"); you may not use this file except in compliance
9    * with the License.  You may obtain a copy of the License at
10   *
11   *   http://www.apache.org/licenses/LICENSE-2.0
12   *
13   * Unless required by applicable law or agreed to in writing,
14   * software distributed under the License is distributed on an
15   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16   * KIND, either express or implied.  See the License for the
17   * specific language governing permissions and limitations
18   * under the License.
19   * ====================================================================
20   *
21   * This software consists of voluntary contributions made by many
22   * individuals on behalf of the Apache Software Foundation.  For more
23   * information on the Apache Software Foundation, please see
24   * <http://www.apache.org/>.
25   */
26  package org.apache.http.impl.client;
27  
28  import java.io.IOException;
29  import java.net.URI;
30  
31  import org.apache.http.HttpEntity;
32  import org.apache.http.HttpEntityEnclosingRequest;
33  import org.apache.http.HttpException;
34  import org.apache.http.HttpHost;
35  import org.apache.http.HttpRequest;
36  import org.apache.http.HttpRequestInterceptor;
37  import org.apache.http.HttpResponse;
38  import org.apache.http.HttpResponseInterceptor;
39  import org.apache.http.client.ClientProtocolException;
40  import org.apache.http.client.HttpClient;
41  import org.apache.http.client.ResponseHandler;
42  import org.apache.http.client.methods.HttpUriRequest;
43  import org.apache.http.client.protocol.RequestAcceptEncoding;
44  import org.apache.http.client.protocol.ResponseContentEncoding;
45  import org.apache.http.client.utils.URIUtils;
46  import org.apache.http.conn.ClientConnectionManager;
47  import org.apache.http.params.HttpParams;
48  import org.apache.http.protocol.BasicHttpContext;
49  import org.apache.http.protocol.HttpContext;
50  import org.apache.http.util.EntityUtils;
51  
52  /**
53   * <p>Decorator adding support for compressed responses. This class sets
54   * the <code>Accept-Encoding</code> header on requests to indicate
55   * support for the <code>gzip</code> and <code>deflate</code>
56   * compression schemes; it then checks the <code>Content-Encoding</code>
57   * header on the response to uncompress any compressed response bodies.
58   * The {@link java.io.InputStream} of the entity will contain the uncompressed
59   * content.</p>
60   * 
61   * <p><b>N.B.</b> Any upstream clients of this class need to be aware that
62   * this effectively obscures visibility into the length of a server
63   * response body, since the <code>Content-Length</code> header will
64   * correspond to the compressed entity length received from the server,
65   * but the content length experienced by reading the response body may
66   * be different (hopefully higher!).</p>
67   * 
68   * <p>That said, this decorator is compatible with the 
69   * <code>CachingHttpClient</code> in that the two decorators can be added 
70   * in either order and still have cacheable responses be cached.</p> 
71   * 
72   * @since 4.2
73   */
74  public class DecompressingHttpClient implements HttpClient {
75  
76      private HttpClient backend;
77      private HttpRequestInterceptor acceptEncodingInterceptor;
78      private HttpResponseInterceptor contentEncodingInterceptor;
79      
80      /**
81       * Constructs a decorator to ask for and handle compressed
82       * entities on the fly.
83       * @param backend the {@link HttpClient} to use for actually
84       *   issuing requests
85       */
86      public DecompressingHttpClient(HttpClient backend) {
87          this(backend, new RequestAcceptEncoding(), new ResponseContentEncoding());
88      }
89      
90      DecompressingHttpClient(HttpClient backend, 
91              HttpRequestInterceptor requestInterceptor, 
92              HttpResponseInterceptor responseInterceptor) {
93          this.backend = backend;
94          this.acceptEncodingInterceptor = requestInterceptor;
95          this.contentEncodingInterceptor = responseInterceptor;
96      }
97  
98      public HttpParams getParams() {
99          return backend.getParams();
100     }
101 
102     public ClientConnectionManager getConnectionManager() {
103         return backend.getConnectionManager();
104     }
105 
106     public HttpResponse execute(HttpUriRequest request) throws IOException,
107             ClientProtocolException {
108         return execute(getHttpHost(request), request, (HttpContext)null);
109     }
110 
111     HttpHost getHttpHost(HttpUriRequest request) {
112         URI uri = request.getURI();
113         return URIUtils.extractHost(uri);
114     }
115 
116     public HttpResponse execute(HttpUriRequest request, HttpContext context)
117             throws IOException, ClientProtocolException {
118         return execute(getHttpHost(request), request, context);
119     }
120 
121     public HttpResponse execute(HttpHost target, HttpRequest request)
122             throws IOException, ClientProtocolException {
123         return execute(target, request, (HttpContext)null);
124     }
125 
126     public HttpResponse execute(HttpHost target, HttpRequest request,
127             HttpContext context) throws IOException, ClientProtocolException {
128         try {
129             if (context == null) context = new BasicHttpContext();
130             HttpRequest wrapped;
131             if (request instanceof HttpEntityEnclosingRequest) {
132                 wrapped = new EntityEnclosingRequestWrapper((HttpEntityEnclosingRequest) request);
133             } else {
134                 wrapped = new RequestWrapper(request);
135             }
136             acceptEncodingInterceptor.process(wrapped, context);
137             HttpResponse response = backend.execute(target, wrapped, context);
138             try {
139                 contentEncodingInterceptor.process(response, context);
140                 if (Boolean.TRUE.equals(context.getAttribute(ResponseContentEncoding.UNCOMPRESSED))) {
141                     response.removeHeaders("Content-Length");
142                     response.removeHeaders("Content-Encoding");
143                     response.removeHeaders("Content-MD5");
144                 }
145                 return response;
146             } catch (HttpException ex) {
147                 EntityUtils.consume(response.getEntity());
148                 throw ex;
149             } catch (IOException ex) {
150                 EntityUtils.consume(response.getEntity());
151                 throw ex;
152             } catch (RuntimeException ex) {
153                 EntityUtils.consume(response.getEntity());
154                 throw ex;
155             }
156         } catch (HttpException e) {
157             throw new ClientProtocolException(e);
158         }
159     }
160 
161     public <T> T execute(HttpUriRequest request,
162             ResponseHandler<? extends T> responseHandler) throws IOException,
163             ClientProtocolException {
164         return execute(getHttpHost(request), request, responseHandler);
165     }
166 
167     public <T> T execute(HttpUriRequest request,
168             ResponseHandler<? extends T> responseHandler, HttpContext context)
169             throws IOException, ClientProtocolException {
170         return execute(getHttpHost(request), request, responseHandler, context);
171     }
172 
173     public <T> T execute(HttpHost target, HttpRequest request,
174             ResponseHandler<? extends T> responseHandler) throws IOException,
175             ClientProtocolException {
176         return execute(target, request, responseHandler, null);
177     }
178 
179     public <T> T execute(HttpHost target, HttpRequest request,
180             ResponseHandler<? extends T> responseHandler, HttpContext context)
181             throws IOException, ClientProtocolException {
182         HttpResponse response = execute(target, request, context);
183         try {
184             return responseHandler.handleResponse(response);
185         } finally {
186             HttpEntity entity = response.getEntity();
187             if (entity != null) EntityUtils.consume(entity);
188         }
189     }
190 
191 }