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  */

27
28 package org.apache.http.impl.client;
29
30 import java.io.Closeable;
31 import java.io.IOException;
32 import java.net.URI;
33
34 import org.apache.commons.logging.Log;
35 import org.apache.commons.logging.LogFactory;
36 import org.apache.http.HttpEntity;
37 import org.apache.http.HttpHost;
38 import org.apache.http.HttpRequest;
39 import org.apache.http.annotation.Contract;
40 import org.apache.http.annotation.ThreadingBehavior;
41 import org.apache.http.client.ClientProtocolException;
42 import org.apache.http.client.HttpClient;
43 import org.apache.http.client.ResponseHandler;
44 import org.apache.http.client.methods.CloseableHttpResponse;
45 import org.apache.http.client.methods.HttpUriRequest;
46 import org.apache.http.client.utils.URIUtils;
47 import org.apache.http.protocol.HttpContext;
48 import org.apache.http.util.Args;
49 import org.apache.http.util.EntityUtils;
50
51 /**
52  * Base implementation of {@link HttpClient} that also implements {@link Closeable}.
53  *
54  * @since 4.3
55  */

56 @Contract(threading = ThreadingBehavior.SAFE)
57 public abstract class CloseableHttpClient implements HttpClient, Closeable {
58
59     private final Log log = LogFactory.getLog(getClass());
60
61     protected abstract CloseableHttpResponse doExecute(HttpHost target, HttpRequest request,
62             HttpContext context) throws IOException, ClientProtocolException;
63
64     /**
65      * {@inheritDoc}
66      */

67     @Override
68     public CloseableHttpResponse execute(
69             final HttpHost target,
70             final HttpRequest request,
71             final HttpContext context) throws IOException, ClientProtocolException {
72         return doExecute(target, request, context);
73     }
74
75     /**
76      * {@inheritDoc}
77      */

78     @Override
79     public CloseableHttpResponse execute(
80             final HttpUriRequest request,
81             final HttpContext context) throws IOException, ClientProtocolException {
82         Args.notNull(request, "HTTP request");
83         return doExecute(determineTarget(request), request, context);
84     }
85
86     private static HttpHost determineTarget(final HttpUriRequest request) throws ClientProtocolException {
87         // A null target may be acceptable if there is a default target.
88         // Otherwise, the null target is detected in the director.
89         HttpHost target = null;
90
91         final URI requestURI = request.getURI();
92         if (requestURI.isAbsolute()) {
93             target = URIUtils.extractHost(requestURI);
94             if (target == null) {
95                 throw new ClientProtocolException("URI does not specify a valid host name: "
96                         + requestURI);
97             }
98         }
99         return target;
100     }
101
102     /**
103      * {@inheritDoc}
104      */

105     @Override
106     public CloseableHttpResponse execute(
107             final HttpUriRequest request) throws IOException, ClientProtocolException {
108         return execute(request, (HttpContext) null);
109     }
110
111     /**
112      * {@inheritDoc}
113      */

114     @Override
115     public CloseableHttpResponse execute(
116             final HttpHost target,
117             final HttpRequest request) throws IOException, ClientProtocolException {
118         return doExecute(target, request, null);
119     }
120
121     /**
122      * Executes a request using the default context and processes the
123      * response using the given response handler. The content entity associated
124      * with the response is fully consumed and the underlying connection is
125      * released back to the connection manager automatically in all cases
126      * relieving individual {@link ResponseHandler}s from having to manage
127      * resource deallocation internally.
128      *
129      * @param request   the request to execute
130      * @param responseHandler the response handler
131      *
132      * @return  the response object as generated by the response handler.
133      * @throws IOException in case of a problem or the connection was aborted
134      * @throws ClientProtocolException in case of an http protocol error
135      */

136     @Override
137     public <T> T execute(final HttpUriRequest request,
138             final ResponseHandler<? extends T> responseHandler) throws IOException,
139             ClientProtocolException {
140         return execute(request, responseHandler, null);
141     }
142
143     /**
144      * Executes a request using the default context and processes the
145      * response using the given response handler. The content entity associated
146      * with the response is fully consumed and the underlying connection is
147      * released back to the connection manager automatically in all cases
148      * relieving individual {@link ResponseHandler}s from having to manage
149      * resource deallocation internally.
150      *
151      * @param request   the request to execute
152      * @param responseHandler the response handler
153      * @param context   the context to use for the execution, or
154      *                  {@code null} to use the default context
155      *
156      * @return  the response object as generated by the response handler.
157      * @throws IOException in case of a problem or the connection was aborted
158      * @throws ClientProtocolException in case of an http protocol error
159      */

160     @Override
161     public <T> T execute(final HttpUriRequest request,
162             final ResponseHandler<? extends T> responseHandler, final HttpContext context)
163             throws IOException, ClientProtocolException {
164         final HttpHost target = determineTarget(request);
165         return execute(target, request, responseHandler, context);
166     }
167
168     /**
169      * Executes a request using the default context and processes the
170      * response using the given response handler. The content entity associated
171      * with the response is fully consumed and the underlying connection is
172      * released back to the connection manager automatically in all cases
173      * relieving individual {@link ResponseHandler}s from having to manage
174      * resource deallocation internally.
175      *
176      * @param target    the target host for the request.
177      *                  Implementations may accept {@code null}
178      *                  if they can still determine a route, for example
179      *                  to a default target or by inspecting the request.
180      * @param request   the request to execute
181      * @param responseHandler the response handler
182      *
183      * @return  the response object as generated by the response handler.
184      * @throws IOException in case of a problem or the connection was aborted
185      * @throws ClientProtocolException in case of an http protocol error
186      */

187     @Override
188     public <T> T execute(final HttpHost target, final HttpRequest request,
189             final ResponseHandler<? extends T> responseHandler) throws IOException,
190             ClientProtocolException {
191         return execute(target, request, responseHandler, null);
192     }
193
194     /**
195      * Executes a request using the default context and processes the
196      * response using the given response handler. The content entity associated
197      * with the response is fully consumed and the underlying connection is
198      * released back to the connection manager automatically in all cases
199      * relieving individual {@link ResponseHandler}s from having to manage
200      * resource deallocation internally.
201      *
202      * @param target    the target host for the request.
203      *                  Implementations may accept {@code null}
204      *                  if they can still determine a route, for example
205      *                  to a default target or by inspecting the request.
206      * @param request   the request to execute
207      * @param responseHandler the response handler
208      * @param context   the context to use for the execution, or
209      *                  {@code null} to use the default context
210      *
211      * @return  the response object as generated by the response handler.
212      * @throws IOException in case of a problem or the connection was aborted
213      * @throws ClientProtocolException in case of an http protocol error
214      */

215     @Override
216     public <T> T execute(final HttpHost target, final HttpRequest request,
217             final ResponseHandler<? extends T> responseHandler, final HttpContext context)
218             throws IOException, ClientProtocolException {
219         Args.notNull(responseHandler, "Response handler");
220
221         final CloseableHttpResponse response = execute(target, request, context);
222         try {
223             final T result = responseHandler.handleResponse(response);
224             final HttpEntity entity = response.getEntity();
225             EntityUtils.consume(entity);
226             return result;
227         } catch (final ClientProtocolException t) {
228             // Try to salvage the underlying connection in case of a protocol exception
229             final HttpEntity entity = response.getEntity();
230             try {
231                 EntityUtils.consume(entity);
232             } catch (final Exception t2) {
233                 // Log this exception. The original exception is more
234                 // important and will be thrown to the caller.
235                 this.log.warn("Error consuming content after an exception.", t2);
236             }
237             throw t;
238         } finally {
239             response.close();
240         }
241     }
242
243 }
244