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