1 /* 2 * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/protocol/HttpRequestExecutor.java $ 3 * $Revision: 576073 $ 4 * $Date: 2007-09-16 03:53:13 -0700 (Sun, 16 Sep 2007) $ 5 * 6 * ==================================================================== 7 * Licensed to the Apache Software Foundation (ASF) under one 8 * or more contributor license agreements. See the NOTICE file 9 * distributed with this work for additional information 10 * regarding copyright ownership. The ASF licenses this file 11 * to you under the Apache License, Version 2.0 (the 12 * "License"); you may not use this file except in compliance 13 * with the License. You may obtain a copy of the License at 14 * 15 * http://www.apache.org/licenses/LICENSE-2.0 16 * 17 * Unless required by applicable law or agreed to in writing, 18 * software distributed under the License is distributed on an 19 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 20 * KIND, either express or implied. See the License for the 21 * specific language governing permissions and limitations 22 * under the License. 23 * ==================================================================== 24 * 25 * This software consists of voluntary contributions made by many 26 * individuals on behalf of the Apache Software Foundation. For more 27 * information on the Apache Software Foundation, please see 28 * <http://www.apache.org/>. 29 * 30 */ 31 32 package org.apache.http.protocol; 33 34 import java.io.IOException; 35 import java.net.ProtocolException; 36 37 import org.apache.http.HttpClientConnection; 38 import org.apache.http.HttpEntityEnclosingRequest; 39 import org.apache.http.HttpException; 40 import org.apache.http.HttpRequest; 41 import org.apache.http.HttpResponse; 42 import org.apache.http.HttpStatus; 43 import org.apache.http.HttpVersion; 44 import org.apache.http.ProtocolVersion; 45 import org.apache.http.params.CoreProtocolPNames; 46 47 /** 48 * Sends HTTP requests and receives the responses. 49 * Takes care of request preprocessing and response postprocessing 50 * by the respective interceptors. 51 * 52 * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a> 53 * 54 * @version $Revision: 576073 $ 55 * 56 * @since 4.0 57 * 58 * @deprecated Please use {@link java.net.URL#openConnection} instead. 59 * Please visit <a href="http://android-developers.blogspot.com/2011/09/androids-http-clients.html">this webpage</a> 60 * for further details. 61 */ 62 @Deprecated 63 public class HttpRequestExecutor { 64 65 /** 66 * Create a new request executor. 67 */ 68 public HttpRequestExecutor() { 69 super(); 70 } 71 72 /** 73 * Decide whether a response comes with an entity. 74 * The implementation in this class is based on RFC 2616. 75 * Unknown methods and response codes are supposed to 76 * indicate responses with an entity. 77 * <br/> 78 * Derived executors can override this method to handle 79 * methods and response codes not specified in RFC 2616. 80 * 81 * @param request the request, to obtain the executed method 82 * @param response the response, to obtain the status code 83 */ 84 protected boolean canResponseHaveBody(final HttpRequest request, 85 final HttpResponse response) { 86 87 if ("HEAD".equalsIgnoreCase(request.getRequestLine().getMethod())) { 88 return false; 89 } 90 int status = response.getStatusLine().getStatusCode(); 91 return status >= HttpStatus.SC_OK 92 && status != HttpStatus.SC_NO_CONTENT 93 && status != HttpStatus.SC_NOT_MODIFIED 94 && status != HttpStatus.SC_RESET_CONTENT; 95 } 96 97 /** 98 * Synchronously send a request and obtain the response. 99 * 100 * @param request the request to send. It will be preprocessed. 101 * @param conn the open connection over which to send 102 * 103 * @return the response to the request, postprocessed 104 * 105 * @throws HttpException in case of a protocol or processing problem 106 * @throws IOException in case of an I/O problem 107 */ 108 public HttpResponse execute( 109 final HttpRequest request, 110 final HttpClientConnection conn, 111 final HttpContext context) 112 throws IOException, HttpException { 113 if (request == null) { 114 throw new IllegalArgumentException("HTTP request may not be null"); 115 } 116 if (conn == null) { 117 throw new IllegalArgumentException("Client connection may not be null"); 118 } 119 if (context == null) { 120 throw new IllegalArgumentException("HTTP context may not be null"); 121 } 122 123 try { 124 HttpResponse response = doSendRequest(request, conn, context); 125 if (response == null) { 126 response = doReceiveResponse(request, conn, context); 127 } 128 return response; 129 } catch (IOException ex) { 130 conn.close(); 131 throw ex; 132 } catch (HttpException ex) { 133 conn.close(); 134 throw ex; 135 } catch (RuntimeException ex) { 136 conn.close(); 137 throw ex; 138 } 139 } 140 141 /** 142 * Prepare a request for sending. 143 * 144 * @param request the request to prepare 145 * @param processor the processor to use 146 * @param context the context for sending the request 147 * 148 * @throws HttpException in case of a protocol or processing problem 149 * @throws IOException in case of an I/O problem 150 */ 151 public void preProcess( 152 final HttpRequest request, 153 final HttpProcessor processor, 154 final HttpContext context) 155 throws HttpException, IOException { 156 if (request == null) { 157 throw new IllegalArgumentException("HTTP request may not be null"); 158 } 159 if (processor == null) { 160 throw new IllegalArgumentException("HTTP processor may not be null"); 161 } 162 if (context == null) { 163 throw new IllegalArgumentException("HTTP context may not be null"); 164 } 165 processor.process(request, context); 166 } 167 168 /** 169 * Send a request over a connection. 170 * This method also handles the expect-continue handshake if necessary. 171 * If it does not have to handle an expect-continue handshake, it will 172 * not use the connection for reading or anything else that depends on 173 * data coming in over the connection. 174 * 175 * @param request the request to send, already 176 * {@link #preProcess preprocessed} 177 * @param conn the connection over which to send the request, 178 * already established 179 * @param context the context for sending the request 180 * 181 * @return a terminal response received as part of an expect-continue 182 * handshake, or 183 * <code>null</code> if the expect-continue handshake is not used 184 * 185 * @throws HttpException in case of a protocol or processing problem 186 * @throws IOException in case of an I/O problem 187 */ 188 protected HttpResponse doSendRequest( 189 final HttpRequest request, 190 final HttpClientConnection conn, 191 final HttpContext context) 192 throws IOException, HttpException { 193 if (request == null) { 194 throw new IllegalArgumentException("HTTP request may not be null"); 195 } 196 if (conn == null) { 197 throw new IllegalArgumentException("HTTP connection may not be null"); 198 } 199 if (context == null) { 200 throw new IllegalArgumentException("HTTP context may not be null"); 201 } 202 203 HttpResponse response = null; 204 context.setAttribute(ExecutionContext.HTTP_REQ_SENT, Boolean.FALSE); 205 206 conn.sendRequestHeader(request); 207 if (request instanceof HttpEntityEnclosingRequest) { 208 // Check for expect-continue handshake. We have to flush the 209 // headers and wait for an 100-continue response to handle it. 210 // If we get a different response, we must not send the entity. 211 boolean sendentity = true; 212 final ProtocolVersion ver = 213 request.getRequestLine().getProtocolVersion(); 214 if (((HttpEntityEnclosingRequest) request).expectContinue() && 215 !ver.lessEquals(HttpVersion.HTTP_1_0)) { 216 217 conn.flush(); 218 // As suggested by RFC 2616 section 8.2.3, we don't wait for a 219 // 100-continue response forever. On timeout, send the entity. 220 int tms = request.getParams().getIntParameter( 221 CoreProtocolPNames.WAIT_FOR_CONTINUE, 2000); 222 223 if (conn.isResponseAvailable(tms)) { 224 response = conn.receiveResponseHeader(); 225 if (canResponseHaveBody(request, response)) { 226 conn.receiveResponseEntity(response); 227 } 228 int status = response.getStatusLine().getStatusCode(); 229 if (status < 200) { 230 if (status != HttpStatus.SC_CONTINUE) { 231 throw new ProtocolException( 232 "Unexpected response: " + response.getStatusLine()); 233 } 234 // discard 100-continue 235 response = null; 236 } else { 237 sendentity = false; 238 } 239 } 240 } 241 if (sendentity) { 242 conn.sendRequestEntity((HttpEntityEnclosingRequest) request); 243 } 244 } 245 conn.flush(); 246 context.setAttribute(ExecutionContext.HTTP_REQ_SENT, Boolean.TRUE); 247 return response; 248 } 249 250 /** 251 * Wait for and receive a response. 252 * This method will automatically ignore intermediate responses 253 * with status code 1xx. 254 * 255 * @param request the request for which to obtain the response 256 * @param conn the connection over which the request was sent 257 * @param context the context for receiving the response 258 * 259 * @return the final response, not yet post-processed 260 * 261 * @throws HttpException in case of a protocol or processing problem 262 * @throws IOException in case of an I/O problem 263 */ 264 protected HttpResponse doReceiveResponse( 265 final HttpRequest request, 266 final HttpClientConnection conn, 267 final HttpContext context) 268 throws HttpException, IOException { 269 if (request == null) { 270 throw new IllegalArgumentException("HTTP request may not be null"); 271 } 272 if (conn == null) { 273 throw new IllegalArgumentException("HTTP connection may not be null"); 274 } 275 if (context == null) { 276 throw new IllegalArgumentException("HTTP context may not be null"); 277 } 278 279 HttpResponse response = null; 280 int statuscode = 0; 281 282 while (response == null || statuscode < HttpStatus.SC_OK) { 283 284 response = conn.receiveResponseHeader(); 285 if (canResponseHaveBody(request, response)) { 286 conn.receiveResponseEntity(response); 287 } 288 statuscode = response.getStatusLine().getStatusCode(); 289 290 } // while intermediate response 291 292 return response; 293 294 } 295 296 /** 297 * Finish a response. 298 * This includes post-processing of the response object. 299 * It does <i>not</i> read the response entity, if any. 300 * It does <i>not</i> allow for immediate re-use of the 301 * connection over which the response is coming in. 302 * 303 * @param response the response object to finish 304 * @param processor the processor to use 305 * @param context the context for post-processing the response 306 * 307 * @throws HttpException in case of a protocol or processing problem 308 * @throws IOException in case of an I/O problem 309 */ 310 public void postProcess( 311 final HttpResponse response, 312 final HttpProcessor processor, 313 final HttpContext context) 314 throws HttpException, IOException { 315 if (response == null) { 316 throw new IllegalArgumentException("HTTP response may not be null"); 317 } 318 if (processor == null) { 319 throw new IllegalArgumentException("HTTP processor may not be null"); 320 } 321 if (context == null) { 322 throw new IllegalArgumentException("HTTP context may not be null"); 323 } 324 processor.process(response, context); 325 } 326 327 } // class HttpRequestExecutor 328