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 }