Home | History | Annotate | Download | only in protocol
      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