Home | History | Annotate | Download | only in net
      1 /*
      2  *  Licensed to the Apache Software Foundation (ASF) under one or more
      3  *  contributor license agreements.  See the NOTICE file distributed with
      4  *  this work for additional information regarding copyright ownership.
      5  *  The ASF licenses this file to You under the Apache License, Version 2.0
      6  *  (the "License"); you may not use this file except in compliance with
      7  *  the License.  You may obtain a copy of the License at
      8  *
      9  *     http://www.apache.org/licenses/LICENSE-2.0
     10  *
     11  *  Unless required by applicable law or agreed to in writing, software
     12  *  distributed under the License is distributed on an "AS IS" BASIS,
     13  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     14  *  See the License for the specific language governing permissions and
     15  *  limitations under the License.
     16  */
     17 
     18 package java.net;
     19 
     20 import java.io.IOException;
     21 import java.io.InputStream;
     22 import java.util.Arrays;
     23 import libcore.net.http.HttpEngine;
     24 
     25 /**
     26  * An {@link URLConnection} for HTTP (<a
     27  * href="http://tools.ietf.org/html/rfc2616">RFC 2616</a>) used to send and
     28  * receive data over the web. Data may be of any type and length. This class may
     29  * be used to send and receive streaming data whose length is not known in
     30  * advance.
     31  *
     32  * <p>Uses of this class follow a pattern:
     33  * <ol>
     34  *   <li>Obtain a new {@code HttpURLConnection} by calling {@link
     35  *       URL#openConnection() URL.openConnection()} and casting the result to
     36  *       {@code HttpURLConnection}.
     37  *   <li>Prepare the request. The primary property of a request is its URI.
     38  *       Request headers may also include metadata such as credentials, preferred
     39  *       content types, and session cookies.
     40  *   <li>Optionally upload a request body. Instances must be configured with
     41  *       {@link #setDoOutput(boolean) setDoOutput(true)} if they include a
     42  *       request body. Transmit data by writing to the stream returned by {@link
     43  *       #getOutputStream()}.
     44  *   <li>Read the response. Response headers typically include metadata such as
     45  *       the response body's content type and length, modified dates and session
     46  *       cookies. The response body may be read from the stream returned by {@link
     47  *       #getInputStream()}. If the response has no body, that method returns an
     48  *       empty stream.
     49  *   <li>Disconnect. Once the response body has been read, the {@code
     50  *       HttpURLConnection} should be closed by calling {@link #disconnect()}.
     51  *       Disconnecting releases the resources held by a connection so they may
     52  *       be closed or reused.
     53  * </ol>
     54  *
     55  * <p>For example, to retrieve the webpage at {@code http://www.android.com/}:
     56  * <pre>   {@code
     57  *   URL url = new URL("http://www.android.com/");
     58  *   HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
     59  *   try {
     60  *     InputStream in = new BufferedInputStream(urlConnection.getInputStream());
     61  *     readStream(in);
     62  *   } finally {
     63  *     urlConnection.disconnect();
     64  *   }
     65  * }</pre>
     66  *
     67  * <h3>Secure Communication with HTTPS</h3>
     68  * Calling {@link URL#openConnection()} on a URL with the "https"
     69  * scheme will return an {@code HttpsURLConnection}, which allows for
     70  * overriding the default {@link javax.net.ssl.HostnameVerifier
     71  * HostnameVerifier} and {@link javax.net.ssl.SSLSocketFactory
     72  * SSLSocketFactory}. An application-supplied {@code SSLSocketFactory}
     73  * created from an {@link javax.net.ssl.SSLContext SSLContext} can
     74  * provide a custom {@link javax.net.ssl.X509TrustManager
     75  * X509TrustManager} for verifying certificate chains and a custom
     76  * {@link javax.net.ssl.X509KeyManager X509KeyManager} for supplying
     77  * client certificates. See {@link javax.net.ssl.HttpsURLConnection
     78  * HttpsURLConnection} for more details.
     79  *
     80  * <h3>Response Handling</h3>
     81  * {@code HttpURLConnection} will follow up to five HTTP redirects. It will
     82  * follow redirects from one origin server to another. This implementation
     83  * doesn't follow redirects from HTTPS to HTTP or vice versa.
     84  *
     85  * <p>If the HTTP response indicates that an error occurred, {@link
     86  * #getInputStream()} will throw an {@link IOException}. Use {@link
     87  * #getErrorStream()} to read the error response. The headers can be read in
     88  * the normal way using {@link #getHeaderFields()},
     89  *
     90  * <h3>Posting Content</h3>
     91  * To upload data to a web server, configure the connection for output using
     92  * {@link #setDoOutput(boolean) setDoOutput(true)}.
     93  *
     94  * <p>For best performance, you should call either {@link
     95  * #setFixedLengthStreamingMode(int)} when the body length is known in advance,
     96  * or {@link #setChunkedStreamingMode(int)} when it is not. Otherwise {@code
     97  * HttpURLConnection} will be forced to buffer the complete request body in
     98  * memory before it is transmitted, wasting (and possibly exhausting) heap and
     99  * increasing latency.
    100  *
    101  * <p>For example, to perform an upload: <pre>   {@code
    102  *   HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
    103  *   try {
    104  *     urlConnection.setDoOutput(true);
    105  *     urlConnection.setChunkedStreamingMode(0);
    106  *
    107  *     OutputStream out = new BufferedOutputStream(urlConnection.getOutputStream());
    108  *     writeStream(out);
    109  *
    110  *     InputStream in = new BufferedInputStream(urlConnection.getInputStream());
    111  *     readStream(in);
    112  *   } finally {
    113  *     urlConnection.disconnect();
    114  *   }
    115  * }</pre>
    116  *
    117  * <h3>Performance</h3>
    118  * The input and output streams returned by this class are <strong>not
    119  * buffered</strong>. Most callers should wrap the returned streams with {@link
    120  * java.io.BufferedInputStream BufferedInputStream} or {@link
    121  * java.io.BufferedOutputStream BufferedOutputStream}. Callers that do only bulk
    122  * reads or writes may omit buffering.
    123  *
    124  * <p>When transferring large amounts of data to or from a server, use streams
    125  * to limit how much data is in memory at once. Unless you need the entire
    126  * body to be in memory at once, process it as a stream (rather than storing
    127  * the complete body as a single byte array or string).
    128  *
    129  * <p>To reduce latency, this class may reuse the same underlying {@code Socket}
    130  * for multiple request/response pairs. As a result, HTTP connections may be
    131  * held open longer than necessary. Calls to {@link #disconnect()} may return
    132  * the socket to a pool of connected sockets. This behavior can be disabled by
    133  * setting the {@code http.keepAlive} system property to {@code false} before
    134  * issuing any HTTP requests. The {@code http.maxConnections} property may be
    135  * used to control how many idle connections to each server will be held.
    136  *
    137  * <p>By default, this implementation of {@code HttpURLConnection} requests that
    138  * servers use gzip compression. Since {@link #getContentLength()} returns the
    139  * number of bytes transmitted, you cannot use that method to predict how many
    140  * bytes can be read from {@link #getInputStream()}. Instead, read that stream
    141  * until it is exhausted: when {@link InputStream#read} returns -1. Gzip
    142  * compression can be disabled by setting the acceptable encodings in the
    143  * request header: <pre>   {@code
    144  *   urlConnection.setRequestProperty("Accept-Encoding", "identity");
    145  * }</pre>
    146  *
    147  * <h3>Handling Network Sign-On</h3>
    148  * Some Wi-Fi networks block Internet access until the user clicks through a
    149  * sign-on page. Such sign-on pages are typically presented by using HTTP
    150  * redirects. You can use {@link #getURL()} to test if your connection has been
    151  * unexpectedly redirected. This check is not valid until <strong>after</strong>
    152  * the response headers have been received, which you can trigger by calling
    153  * {@link #getHeaderFields()} or {@link #getInputStream()}. For example, to
    154  * check that a response was not redirected to an unexpected host:
    155  * <pre>   {@code
    156  *   HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
    157  *   try {
    158  *     InputStream in = new BufferedInputStream(urlConnection.getInputStream());
    159  *     if (!url.getHost().equals(urlConnection.getURL().getHost())) {
    160  *       // we were redirected! Kick the user out to the browser to sign on?
    161  *     }
    162  *     ...
    163  *   } finally {
    164  *     urlConnection.disconnect();
    165  *   }
    166  * }</pre>
    167  *
    168  * <h3>HTTP Authentication</h3>
    169  * {@code HttpURLConnection} supports <a
    170  * href="http://www.ietf.org/rfc/rfc2617">HTTP basic authentication</a>. Use
    171  * {@link Authenticator} to set the VM-wide authentication handler:
    172  * <pre>   {@code
    173  *   Authenticator.setDefault(new Authenticator() {
    174  *     protected PasswordAuthentication getPasswordAuthentication() {
    175  *       return new PasswordAuthentication(username, password.toCharArray());
    176  *     }
    177  *   });
    178  * }</pre>
    179  * Unless paired with HTTPS, this is <strong>not</strong> a secure mechanism for
    180  * user authentication. In particular, the username, password, request and
    181  * response are all transmitted over the network without encryption.
    182  *
    183  * <h3>Sessions with Cookies</h3>
    184  * To establish and maintain a potentially long-lived session between client
    185  * and server, {@code HttpURLConnection} includes an extensible cookie manager.
    186  * Enable VM-wide cookie management using {@link CookieHandler} and {@link
    187  * CookieManager}: <pre>   {@code
    188  *   CookieManager cookieManager = new CookieManager();
    189  *   CookieHandler.setDefault(cookieManager);
    190  * }</pre>
    191  * By default, {@code CookieManager} accepts cookies from the <a
    192  * href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec1.html">origin
    193  * server</a> only. Two other policies are included: {@link
    194  * CookiePolicy#ACCEPT_ALL} and {@link CookiePolicy#ACCEPT_NONE}. Implement
    195  * {@link CookiePolicy} to define a custom policy.
    196  *
    197  * <p>The default {@code CookieManager} keeps all accepted cookies in memory. It
    198  * will forget these cookies when the VM exits. Implement {@link CookieStore} to
    199  * define a custom cookie store.
    200  *
    201  * <p>In addition to the cookies set by HTTP responses, you may set cookies
    202  * programmatically. To be included in HTTP request headers, cookies must have
    203  * the domain and path properties set.
    204  *
    205  * <p>By default, new instances of {@code HttpCookie} work only with servers
    206  * that support <a href="http://www.ietf.org/rfc/rfc2965.txt">RFC 2965</a>
    207  * cookies. Many web servers support only the older specification, <a
    208  * href="http://www.ietf.org/rfc/rfc2109.txt">RFC 2109</a>. For compatibility
    209  * with the most web servers, set the cookie version to 0.
    210  *
    211  * <p>For example, to receive {@code www.twitter.com} in French: <pre>   {@code
    212  *   HttpCookie cookie = new HttpCookie("lang", "fr");
    213  *   cookie.setDomain("twitter.com");
    214  *   cookie.setPath("/");
    215  *   cookie.setVersion(0);
    216  *   cookieManager.getCookieStore().add(new URI("http://twitter.com/"), cookie);
    217  * }</pre>
    218  *
    219  * <h3>HTTP Methods</h3>
    220  * <p>{@code HttpURLConnection} uses the {@code GET} method by default. It will
    221  * use {@code POST} if {@link #setDoOutput setDoOutput(true)} has been called.
    222  * Other HTTP methods ({@code OPTIONS}, {@code HEAD}, {@code PUT}, {@code
    223  * DELETE} and {@code TRACE}) can be used with {@link #setRequestMethod}.
    224  *
    225  * <h3>Proxies</h3>
    226  * By default, this class will connect directly to the <a
    227  * href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec1.html">origin
    228  * server</a>. It can also connect via an {@link Proxy.Type#HTTP HTTP} or {@link
    229  * Proxy.Type#SOCKS SOCKS} proxy. To use a proxy, use {@link
    230  * URL#openConnection(Proxy) URL.openConnection(Proxy)} when creating the
    231  * connection.
    232  *
    233  * <h3>IPv6 Support</h3>
    234  * <p>This class includes transparent support for IPv6. For hosts with both IPv4
    235  * and IPv6 addresses, it will attempt to connect to each of a host's addresses
    236  * until a connection is established.
    237  *
    238  * <h3>Response Caching</h3>
    239  * Android 4.0 (Ice Cream Sandwich) includes a response cache. See {@code
    240  * android.net.http.HttpResponseCache} for instructions on enabling HTTP caching
    241  * in your application.
    242  *
    243  * <h3>Avoiding Bugs In Earlier Releases</h3>
    244  * Prior to Android 2.2 (Froyo), this class had some frustrating bugs. In
    245  * particular, calling {@code close()} on a readable {@code InputStream} could
    246  * <a href="http://code.google.com/p/android/issues/detail?id=2939">poison the
    247  * connection pool</a>. Work around this by disabling connection pooling:
    248  * <pre>   {@code
    249  * private void disableConnectionReuseIfNecessary() {
    250  *   // Work around pre-Froyo bugs in HTTP connection reuse.
    251  *   if (Integer.parseInt(Build.VERSION.SDK) < Build.VERSION_CODES.FROYO) {
    252  *     System.setProperty("http.keepAlive", "false");
    253  *   }
    254  * }}</pre>
    255  *
    256  * <p>Each instance of {@code HttpURLConnection} may be used for one
    257  * request/response pair. Instances of this class are not thread safe.
    258  */
    259 public abstract class HttpURLConnection extends URLConnection {
    260 
    261     /**
    262      * The subset of HTTP methods that the user may select via {@link
    263      * #setRequestMethod(String)}.
    264      */
    265     private static final String[] PERMITTED_USER_METHODS = {
    266             HttpEngine.OPTIONS,
    267             HttpEngine.GET,
    268             HttpEngine.HEAD,
    269             HttpEngine.POST,
    270             HttpEngine.PUT,
    271             HttpEngine.DELETE,
    272             HttpEngine.TRACE
    273             // Note: we don't allow users to specify "CONNECT"
    274     };
    275 
    276     /**
    277      * The HTTP request method of this {@code HttpURLConnection}. The default
    278      * value is {@code "GET"}.
    279      */
    280     protected String method = HttpEngine.GET;
    281 
    282     /**
    283      * The status code of the response obtained from the HTTP request. The
    284      * default value is {@code -1}.
    285      * <p>
    286      * <li>1xx: Informational</li>
    287      * <li>2xx: Success</li>
    288      * <li>3xx: Relocation/Redirection</li>
    289      * <li>4xx: Client Error</li>
    290      * <li>5xx: Server Error</li>
    291      */
    292     protected int responseCode = -1;
    293 
    294     /**
    295      * The HTTP response message which corresponds to the response code.
    296      */
    297     protected String responseMessage;
    298 
    299     /**
    300      * Flag to define whether the protocol will automatically follow redirects
    301      * or not. The default value is {@code true}.
    302      */
    303     protected boolean instanceFollowRedirects = followRedirects;
    304 
    305     private static boolean followRedirects = true;
    306 
    307     /**
    308      * If the HTTP chunked encoding is enabled this parameter defines the
    309      * chunk-length. Default value is {@code -1} that means the chunked encoding
    310      * mode is disabled.
    311      */
    312     protected int chunkLength = -1;
    313 
    314     /**
    315      * If using HTTP fixed-length streaming mode this parameter defines the
    316      * fixed length of content. Default value is {@code -1} that means the
    317      * fixed-length streaming mode is disabled.
    318      */
    319     protected int fixedContentLength = -1;
    320 
    321     // 2XX: generally "OK"
    322     // 3XX: relocation/redirect
    323     // 4XX: client error
    324     // 5XX: server error
    325     /**
    326      * Numeric status code, 202: Accepted
    327      */
    328     public static final int HTTP_ACCEPTED = 202;
    329 
    330     /**
    331      * Numeric status code, 502: Bad Gateway
    332      */
    333     public static final int HTTP_BAD_GATEWAY = 502;
    334 
    335     /**
    336      * Numeric status code, 405: Bad Method
    337      */
    338     public static final int HTTP_BAD_METHOD = 405;
    339 
    340     /**
    341      * Numeric status code, 400: Bad Request
    342      */
    343     public static final int HTTP_BAD_REQUEST = 400;
    344 
    345     /**
    346      * Numeric status code, 408: Client Timeout
    347      */
    348     public static final int HTTP_CLIENT_TIMEOUT = 408;
    349 
    350     /**
    351      * Numeric status code, 409: Conflict
    352      */
    353     public static final int HTTP_CONFLICT = 409;
    354 
    355     /**
    356      * Numeric status code, 201: Created
    357      */
    358     public static final int HTTP_CREATED = 201;
    359 
    360     /**
    361      * Numeric status code, 413: Entity too large
    362      */
    363     public static final int HTTP_ENTITY_TOO_LARGE = 413;
    364 
    365     /**
    366      * Numeric status code, 403: Forbidden
    367      */
    368     public static final int HTTP_FORBIDDEN = 403;
    369 
    370     /**
    371      * Numeric status code, 504: Gateway timeout
    372      */
    373     public static final int HTTP_GATEWAY_TIMEOUT = 504;
    374 
    375     /**
    376      * Numeric status code, 410: Gone
    377      */
    378     public static final int HTTP_GONE = 410;
    379 
    380     /**
    381      * Numeric status code, 500: Internal error
    382      */
    383     public static final int HTTP_INTERNAL_ERROR = 500;
    384 
    385     /**
    386      * Numeric status code, 411: Length required
    387      */
    388     public static final int HTTP_LENGTH_REQUIRED = 411;
    389 
    390     /**
    391      * Numeric status code, 301 Moved permanently
    392      */
    393     public static final int HTTP_MOVED_PERM = 301;
    394 
    395     /**
    396      * Numeric status code, 302: Moved temporarily
    397      */
    398     public static final int HTTP_MOVED_TEMP = 302;
    399 
    400     /**
    401      * Numeric status code, 300: Multiple choices
    402      */
    403     public static final int HTTP_MULT_CHOICE = 300;
    404 
    405     /**
    406      * Numeric status code, 204: No content
    407      */
    408     public static final int HTTP_NO_CONTENT = 204;
    409 
    410     /**
    411      * Numeric status code, 406: Not acceptable
    412      */
    413     public static final int HTTP_NOT_ACCEPTABLE = 406;
    414 
    415     /**
    416      * Numeric status code, 203: Not authoritative
    417      */
    418     public static final int HTTP_NOT_AUTHORITATIVE = 203;
    419 
    420     /**
    421      * Numeric status code, 404: Not found
    422      */
    423     public static final int HTTP_NOT_FOUND = 404;
    424 
    425     /**
    426      * Numeric status code, 501: Not implemented
    427      */
    428     public static final int HTTP_NOT_IMPLEMENTED = 501;
    429 
    430     /**
    431      * Numeric status code, 304: Not modified
    432      */
    433     public static final int HTTP_NOT_MODIFIED = 304;
    434 
    435     /**
    436      * Numeric status code, 200: OK
    437      */
    438     public static final int HTTP_OK = 200;
    439 
    440     /**
    441      * Numeric status code, 206: Partial
    442      */
    443     public static final int HTTP_PARTIAL = 206;
    444 
    445     /**
    446      * Numeric status code, 402: Payment required
    447      */
    448     public static final int HTTP_PAYMENT_REQUIRED = 402;
    449 
    450     /**
    451      * Numeric status code, 412: Precondition failed
    452      */
    453     public static final int HTTP_PRECON_FAILED = 412;
    454 
    455     /**
    456      * Numeric status code, 407: Proxy authentication required
    457      */
    458     public static final int HTTP_PROXY_AUTH = 407;
    459 
    460     /**
    461      * Numeric status code, 414: Request too long
    462      */
    463     public static final int HTTP_REQ_TOO_LONG = 414;
    464 
    465     /**
    466      * Numeric status code, 205: Reset
    467      */
    468     public static final int HTTP_RESET = 205;
    469 
    470     /**
    471      * Numeric status code, 303: See other
    472      */
    473     public static final int HTTP_SEE_OTHER = 303;
    474 
    475     /**
    476      * Numeric status code, 500: Internal error
    477      *
    478      * @deprecated Use {@link #HTTP_INTERNAL_ERROR}
    479      */
    480     @Deprecated
    481     public static final int HTTP_SERVER_ERROR = 500;
    482 
    483     /**
    484      * Numeric status code, 305: Use proxy.
    485      *
    486      * <p>Like Firefox and Chrome, this class doesn't honor this response code.
    487      * Other implementations respond to this status code by retrying the request
    488      * using the HTTP proxy named by the response's Location header field.
    489      */
    490     public static final int HTTP_USE_PROXY = 305;
    491 
    492     /**
    493      * Numeric status code, 401: Unauthorized
    494      */
    495     public static final int HTTP_UNAUTHORIZED = 401;
    496 
    497     /**
    498      * Numeric status code, 415: Unsupported type
    499      */
    500     public static final int HTTP_UNSUPPORTED_TYPE = 415;
    501 
    502     /**
    503      * Numeric status code, 503: Unavailable
    504      */
    505     public static final int HTTP_UNAVAILABLE = 503;
    506 
    507     /**
    508      * Numeric status code, 505: Version not supported
    509      */
    510     public static final int HTTP_VERSION = 505;
    511 
    512     /**
    513      * Constructs a new {@code HttpURLConnection} instance pointing to the
    514      * resource specified by the {@code url}.
    515      *
    516      * @param url
    517      *            the URL of this connection.
    518      * @see URL
    519      * @see URLConnection
    520      */
    521     protected HttpURLConnection(URL url) {
    522         super(url);
    523     }
    524 
    525     /**
    526      * Releases this connection so that its resources may be either reused or
    527      * closed.
    528      *
    529      * <p>Unlike other Java implementations, this will not necessarily close
    530      * socket connections that can be reused. You can disable all connection
    531      * reuse by setting the {@code http.keepAlive} system property to {@code
    532      * false} before issuing any HTTP requests.
    533      */
    534     public abstract void disconnect();
    535 
    536     /**
    537      * Returns an input stream from the server in the case of an error such as
    538      * the requested file has not been found on the remote server. This stream
    539      * can be used to read the data the server will send back.
    540      *
    541      * @return the error input stream returned by the server.
    542      */
    543     public InputStream getErrorStream() {
    544         return null;
    545     }
    546 
    547     /**
    548      * Returns the value of {@code followRedirects} which indicates if this
    549      * connection follows a different URL redirected by the server. It is
    550      * enabled by default.
    551      *
    552      * @return the value of the flag.
    553      * @see #setFollowRedirects
    554      */
    555     public static boolean getFollowRedirects() {
    556         return followRedirects;
    557     }
    558 
    559     /**
    560      * Returns the permission object (in this case {@code SocketPermission})
    561      * with the host and the port number as the target name and {@code
    562      * "resolve, connect"} as the action list. If the port number of this URL
    563      * instance is lower than {@code 0} the port will be set to {@code 80}.
    564      *
    565      * @return the permission object required for this connection.
    566      * @throws IOException
    567      *             if an IO exception occurs during the creation of the
    568      *             permission object.
    569      */
    570     @Override
    571     public java.security.Permission getPermission() throws IOException {
    572         int port = url.getPort();
    573         if (port < 0) {
    574             port = 80;
    575         }
    576         return new SocketPermission(url.getHost() + ":" + port,
    577                 "connect, resolve");
    578     }
    579 
    580     /**
    581      * Returns the request method which will be used to make the request to the
    582      * remote HTTP server. All possible methods of this HTTP implementation is
    583      * listed in the class definition.
    584      *
    585      * @return the request method string.
    586      * @see #method
    587      * @see #setRequestMethod
    588      */
    589     public String getRequestMethod() {
    590         return method;
    591     }
    592 
    593     /**
    594      * Returns the response code returned by the remote HTTP server.
    595      *
    596      * @return the response code, -1 if no valid response code.
    597      * @throws IOException
    598      *             if there is an IO error during the retrieval.
    599      * @see #getResponseMessage
    600      */
    601     public int getResponseCode() throws IOException {
    602         // Call getInputStream() first since getHeaderField() doesn't return
    603         // exceptions
    604         getInputStream();
    605         String response = getHeaderField(0);
    606         if (response == null) {
    607             return -1;
    608         }
    609         response = response.trim();
    610         int mark = response.indexOf(" ") + 1;
    611         if (mark == 0) {
    612             return -1;
    613         }
    614         int last = mark + 3;
    615         if (last > response.length()) {
    616             last = response.length();
    617         }
    618         responseCode = Integer.parseInt(response.substring(mark, last));
    619         if (last + 1 <= response.length()) {
    620             responseMessage = response.substring(last + 1);
    621         }
    622         return responseCode;
    623     }
    624 
    625     /**
    626      * Returns the response message returned by the remote HTTP server.
    627      *
    628      * @return the response message. {@code null} if no such response exists.
    629      * @throws IOException
    630      *             if there is an error during the retrieval.
    631      * @see #getResponseCode()
    632      */
    633     public String getResponseMessage() throws IOException {
    634         if (responseMessage != null) {
    635             return responseMessage;
    636         }
    637         getResponseCode();
    638         return responseMessage;
    639     }
    640 
    641     /**
    642      * Sets the flag of whether this connection will follow redirects returned
    643      * by the remote server.
    644      *
    645      * @param auto
    646      *            the value to enable or disable this option.
    647      */
    648     public static void setFollowRedirects(boolean auto) {
    649         followRedirects = auto;
    650     }
    651 
    652     /**
    653      * Sets the request command which will be sent to the remote HTTP server.
    654      * This method can only be called before the connection is made.
    655      *
    656      * @param method
    657      *            the string representing the method to be used.
    658      * @throws ProtocolException
    659      *             if this is called after connected, or the method is not
    660      *             supported by this HTTP implementation.
    661      * @see #getRequestMethod()
    662      * @see #method
    663      */
    664     public void setRequestMethod(String method) throws ProtocolException {
    665         if (connected) {
    666             throw new ProtocolException("Connection already established");
    667         }
    668         for (String permittedUserMethod : PERMITTED_USER_METHODS) {
    669             if (permittedUserMethod.equals(method)) {
    670                 // if there is a supported method that matches the desired
    671                 // method, then set the current method and return
    672                 this.method = permittedUserMethod;
    673                 return;
    674             }
    675         }
    676         // if none matches, then throw ProtocolException
    677         throw new ProtocolException("Unknown method '" + method + "'; must be one of " +
    678                 Arrays.toString(PERMITTED_USER_METHODS));
    679     }
    680 
    681     /**
    682      * Returns whether this connection uses a proxy server or not.
    683      *
    684      * @return {@code true} if this connection passes a proxy server, false
    685      *         otherwise.
    686      */
    687     public abstract boolean usingProxy();
    688 
    689     /**
    690      * Returns the encoding used to transmit the response body over the network.
    691      * This is null or "identity" if the content was not encoded, or "gzip" if
    692      * the body was gzip compressed. Most callers will be more interested in the
    693      * {@link #getContentType() content type}, which may also include the
    694      * content's character encoding.
    695      */
    696     @Override public String getContentEncoding() {
    697         return super.getContentEncoding(); // overridden for Javadoc only
    698     }
    699 
    700     /**
    701      * Returns whether this connection follows redirects.
    702      *
    703      * @return {@code true} if this connection follows redirects, false
    704      *         otherwise.
    705      */
    706     public boolean getInstanceFollowRedirects() {
    707         return instanceFollowRedirects;
    708     }
    709 
    710     /**
    711      * Sets whether this connection follows redirects.
    712      *
    713      * @param followRedirects
    714      *            {@code true} if this connection will follows redirects, false
    715      *            otherwise.
    716      */
    717     public void setInstanceFollowRedirects(boolean followRedirects) {
    718         instanceFollowRedirects = followRedirects;
    719     }
    720 
    721     /**
    722      * Returns the date value in milliseconds since {@code 01.01.1970, 00:00h}
    723      * corresponding to the header field {@code field}. The {@code defaultValue}
    724      * will be returned if no such field can be found in the response header.
    725      *
    726      * @param field
    727      *            the header field name.
    728      * @param defaultValue
    729      *            the default value to use if the specified header field wont be
    730      *            found.
    731      * @return the header field represented in milliseconds since January 1,
    732      *         1970 GMT.
    733      */
    734     @Override
    735     public long getHeaderFieldDate(String field, long defaultValue) {
    736         return super.getHeaderFieldDate(field, defaultValue);
    737     }
    738 
    739     /**
    740      * If the length of a HTTP request body is known ahead, sets fixed length to
    741      * enable streaming without buffering. Sets after connection will cause an
    742      * exception.
    743      *
    744      * @see #setChunkedStreamingMode
    745      * @param contentLength
    746      *            the fixed length of the HTTP request body.
    747      * @throws IllegalStateException
    748      *             if already connected or another mode already set.
    749      * @throws IllegalArgumentException
    750      *             if {@code contentLength} is less than zero.
    751      */
    752     public void setFixedLengthStreamingMode(int contentLength) {
    753         if (super.connected) {
    754             throw new IllegalStateException("Already connected");
    755         }
    756         if (chunkLength > 0) {
    757             throw new IllegalStateException("Already in chunked mode");
    758         }
    759         if (contentLength < 0) {
    760             throw new IllegalArgumentException("contentLength < 0");
    761         }
    762         this.fixedContentLength = contentLength;
    763     }
    764 
    765     /**
    766      * Stream a request body whose length is not known in advance. Old HTTP/1.0
    767      * only servers may not support this mode.
    768      *
    769      * <p>When HTTP chunked encoding is used, the stream is divided into
    770      * chunks, each prefixed with a header containing the chunk's size. Setting
    771      * a large chunk length requires a large internal buffer, potentially
    772      * wasting memory. Setting a small chunk length increases the number of
    773      * bytes that must be transmitted because of the header on every chunk.
    774      * Most caller should use {@code 0} to get the system default.
    775      *
    776      * @see #setFixedLengthStreamingMode
    777      * @param chunkLength the length to use, or {@code 0} for the default chunk
    778      *     length.
    779      * @throws IllegalStateException if already connected or another mode
    780      *     already set.
    781      */
    782     public void setChunkedStreamingMode(int chunkLength) {
    783         if (super.connected) {
    784             throw new IllegalStateException("Already connected");
    785         }
    786         if (fixedContentLength >= 0) {
    787             throw new IllegalStateException("Already in fixed-length mode");
    788         }
    789         if (chunkLength <= 0) {
    790             this.chunkLength = HttpEngine.DEFAULT_CHUNK_LENGTH;
    791         } else {
    792             this.chunkLength = chunkLength;
    793         }
    794     }
    795 }
    796