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   */
27  
28  package org.apache.hc.client5.http.impl.classic;
29  
30  import java.io.IOException;
31  
32  import org.apache.hc.client5.http.ClientProtocolException;
33  import org.apache.hc.client5.http.classic.HttpClient;
34  import org.apache.hc.client5.http.routing.RoutingSupport;
35  import org.apache.hc.core5.annotation.Contract;
36  import org.apache.hc.core5.annotation.ThreadingBehavior;
37  import org.apache.hc.core5.http.ClassicHttpRequest;
38  import org.apache.hc.core5.http.ClassicHttpResponse;
39  import org.apache.hc.core5.http.HttpEntity;
40  import org.apache.hc.core5.http.HttpException;
41  import org.apache.hc.core5.http.HttpHost;
42  import org.apache.hc.core5.http.io.HttpClientResponseHandler;
43  import org.apache.hc.core5.http.io.entity.EntityUtils;
44  import org.apache.hc.core5.http.protocol.HttpContext;
45  import org.apache.hc.core5.io.ModalCloseable;
46  import org.apache.hc.core5.util.Args;
47  import org.slf4j.Logger;
48  import org.slf4j.LoggerFactory;
49  
50  /**
51   * Base implementation of {@link HttpClient} that also implements {@link ModalCloseable}.
52   *
53   * @since 4.3
54   */
55  @Contract(threading = ThreadingBehavior.SAFE)
56  public abstract class CloseableHttpClient implements HttpClient, ModalCloseable {
57  
58      private static final Logger LOG = LoggerFactory.getLogger(CloseableHttpClient.class);
59  
60      protected abstract CloseableHttpResponse doExecute(HttpHost target, ClassicHttpRequest request,
61                                                         HttpContext context) throws IOException;
62  
63      private static HttpHost determineTarget(final ClassicHttpRequest request) throws ClientProtocolException {
64          try {
65              return RoutingSupport.determineHost(request);
66          } catch (final HttpException ex) {
67              throw new ClientProtocolException(ex);
68          }
69      }
70  
71      /**
72       * @deprecated It is strongly recommended to use execute methods with {@link HttpClientResponseHandler}
73       * such as {@link #execute(HttpHost, ClassicHttpRequest, HttpContext, HttpClientResponseHandler)} in order
74       * to ensure automatic resource deallocation by the client.
75       * For special cases one can still use {@link #executeOpen(HttpHost, ClassicHttpRequest, HttpContext)}
76       * to keep the response object open after the request execution.
77       *
78       * @see #execute(HttpHost, ClassicHttpRequest, HttpContext, HttpClientResponseHandler)
79       * @see #executeOpen(HttpHost, ClassicHttpRequest, HttpContext)
80       */
81      @Deprecated
82      @Override
83      public CloseableHttpResponse execute(
84              final HttpHost target,
85              final ClassicHttpRequest request,
86              final HttpContext context) throws IOException {
87          return doExecute(target, request, context);
88      }
89  
90      /**
91       * @deprecated It is strongly recommended to use execute methods with {@link HttpClientResponseHandler}
92       * such as {@link #execute(ClassicHttpRequest, HttpContext, HttpClientResponseHandler)} in order
93       * to ensure automatic resource deallocation by the client.
94       * For special cases one can still use {@link #executeOpen(HttpHost, ClassicHttpRequest, HttpContext)}
95       * to keep the response object open after the request execution.
96       *
97       * @see #execute(ClassicHttpRequest, HttpContext, HttpClientResponseHandler)
98       * @see #executeOpen(HttpHost, ClassicHttpRequest, HttpContext)
99       */
100     @Deprecated
101     @Override
102     public CloseableHttpResponse execute(
103             final ClassicHttpRequest request,
104             final HttpContext context) throws IOException {
105         Args.notNull(request, "HTTP request");
106         return doExecute(determineTarget(request), request, context);
107     }
108 
109     /**
110      * @deprecated It is strongly recommended to use execute methods with {@link HttpClientResponseHandler}
111      * such as {@link #execute(ClassicHttpRequest, HttpClientResponseHandler)} in order
112      * to ensure automatic resource deallocation by the client.
113      * For special cases one can still use {@link #executeOpen(HttpHost, ClassicHttpRequest, HttpContext)}
114      * to keep the response object open after the request execution.
115      *
116      * @see #execute(ClassicHttpRequest, HttpClientResponseHandler)
117      * @see #executeOpen(HttpHost, ClassicHttpRequest, HttpContext)
118      */
119     @Deprecated
120     @Override
121     public CloseableHttpResponse execute(
122             final ClassicHttpRequest request) throws IOException {
123         return doExecute(determineTarget(request), request, null);
124     }
125 
126     /**
127      * @deprecated It is strongly recommended to use execute methods with {@link HttpClientResponseHandler}
128      * such as {@link #execute(HttpHost, ClassicHttpRequest, HttpClientResponseHandler)} in order
129      * to ensure automatic resource deallocation by the client.
130      * For special cases one can still use {@link #executeOpen(HttpHost, ClassicHttpRequest, HttpContext)}
131      * to keep the response object open after the request execution.
132      *
133      * @see #execute(HttpHost, ClassicHttpRequest, HttpClientResponseHandler)
134      * @see #executeOpen(HttpHost, ClassicHttpRequest, HttpContext)
135      */
136     @Deprecated
137     @Override
138     public CloseableHttpResponse execute(
139             final HttpHost target,
140             final ClassicHttpRequest request) throws IOException {
141         return doExecute(target, request, null);
142     }
143 
144     /**
145      * Executes a request using the default context and processes the
146      * response using the given response handler. The content entity associated
147      * with the response is fully consumed and the underlying connection is
148      * released back to the connection manager automatically in all cases
149      * relieving individual {@link HttpClientResponseHandler}s from having to manage
150      * resource deallocation internally.
151      *
152      * @param request   the request to execute
153      * @param responseHandler the response handler
154      *
155      * @return  the response object as generated by the response handler.
156      * @throws IOException in case of a problem or the connection was aborted
157      * @throws ClientProtocolException in case of an http protocol error
158      */
159     @Override
160     public <T> T execute(final ClassicHttpRequest request,
161             final HttpClientResponseHandler<? extends T> responseHandler) throws IOException {
162         return execute(request, null, responseHandler);
163     }
164 
165     /**
166      * Executes a request using the default context and processes the
167      * response using the given response handler. The content entity associated
168      * with the response is fully consumed and the underlying connection is
169      * released back to the connection manager automatically in all cases
170      * relieving individual {@link HttpClientResponseHandler}s from having to manage
171      * resource deallocation internally.
172      *
173      * @param request   the request to execute
174      * @param responseHandler the response handler
175      * @param context   the context to use for the execution, or
176      *                  {@code null} to use the default context
177      *
178      * @return  the response object as generated by the response handler.
179      * @throws IOException in case of a problem or the connection was aborted
180      * @throws ClientProtocolException in case of an http protocol error
181      */
182     @Override
183     public <T> T execute(
184             final ClassicHttpRequest request,
185             final HttpContext context,
186             final HttpClientResponseHandler<? extends T> responseHandler) throws IOException {
187         final HttpHost target = determineTarget(request);
188         return execute(target, request, context, responseHandler);
189     }
190 
191     /**
192      * Executes a request using the default context and processes the
193      * response using the given response handler. The content entity associated
194      * with the response is fully consumed and the underlying connection is
195      * released back to the connection manager automatically in all cases
196      * relieving individual {@link HttpClientResponseHandler}s from having to manage
197      * resource deallocation internally.
198      *
199      * @param target    the target host for the request.
200      *                  Implementations may accept {@code null}
201      *                  if they can still determine a route, for example
202      *                  to a default target or by inspecting the request.
203      * @param request   the request to execute
204      * @param responseHandler the response handler
205      *
206      * @return  the response object as generated by the response handler.
207      * @throws IOException in case of a problem or the connection was aborted
208      * @throws ClientProtocolException in case of an http protocol error
209      */
210     @Override
211     public <T> T execute(final HttpHost target, final ClassicHttpRequest request,
212             final HttpClientResponseHandler<? extends T> responseHandler) throws IOException {
213         return execute(target, request, null, responseHandler);
214     }
215 
216     /**
217      * Executes a request using the default context and processes the
218      * response using the given response handler. The content entity associated
219      * with the response is fully consumed and the underlying connection is
220      * released back to the connection manager automatically in all cases
221      * relieving individual {@link HttpClientResponseHandler}s from having to manage
222      * resource deallocation internally.
223      *
224      * @param target    the target host for the request.
225      *                  Implementations may accept {@code null}
226      *                  if they can still determine a route, for example
227      *                  to a default target or by inspecting the request.
228      * @param request   the request to execute
229      * @param context   the context to use for the execution, or
230      *                  {@code null} to use the default context
231      * @param responseHandler the response handler
232      *
233      * @return  the response object as generated by the response handler.
234      * @throws IOException in case of a problem or the connection was aborted
235      * @throws ClientProtocolException in case of an http protocol error
236      */
237     @Override
238     public <T> T execute(
239             final HttpHost target,
240             final ClassicHttpRequest request,
241             final HttpContext context,
242             final HttpClientResponseHandler<? extends T> responseHandler) throws IOException {
243         Args.notNull(responseHandler, "Response handler");
244 
245         try (final ClassicHttpResponse response = doExecute(target, request, context)) {
246             try {
247                 final T result = responseHandler.handleResponse(response);
248                 final HttpEntity entity = response.getEntity();
249                 EntityUtils.consume(entity);
250                 return result;
251             } catch (final HttpException t) {
252                 // Try to salvage the underlying connection in case of a protocol exception
253                 final HttpEntity entity = response.getEntity();
254                 try {
255                     EntityUtils.consume(entity);
256                 } catch (final Exception t2) {
257                     // Log this exception. The original exception is more
258                     // important and will be thrown to the caller.
259                     LOG.warn("Error consuming content after an exception.", t2);
260                 }
261                 throw new ClientProtocolException(t);
262             }
263         }
264     }
265 
266 }