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