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