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
18package java.net;
19
20import java.io.IOException;
21import java.io.InputStream;
22import 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 and it automatically decompresses the data for
138 * callers of {@link #getInputStream()}. The Content-Encoding and Content-Length
139 * response headers are cleared in this case. Gzip compression can be disabled by
140 * setting the acceptable encodings in the request header: <pre>   {@code
141 *   urlConnection.setRequestProperty("Accept-Encoding", "identity");
142 * }</pre>
143 *
144 * <p>Setting the Accept-Encoding request header explicitly disables automatic
145 * decompression and leaves the response headers intact; callers must handle
146 * decompression as needed, according to the Content-Encoding header of the
147 * response.
148 *
149 * <p>{@link #getContentLength()} returns the number of bytes transmitted and
150 * cannot be used to predict how many bytes can be read from
151 * {@link #getInputStream()} for compressed streams. Instead, read that stream
152 * until it is exhausted, i.e. when {@link InputStream#read} returns -1.
153 *
154 * <h3>Handling Network Sign-On</h3>
155 * Some Wi-Fi networks block Internet access until the user clicks through a
156 * sign-on page. Such sign-on pages are typically presented by using HTTP
157 * redirects. You can use {@link #getURL()} to test if your connection has been
158 * unexpectedly redirected. This check is not valid until <strong>after</strong>
159 * the response headers have been received, which you can trigger by calling
160 * {@link #getHeaderFields()} or {@link #getInputStream()}. For example, to
161 * check that a response was not redirected to an unexpected host:
162 * <pre>   {@code
163 *   HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
164 *   try {
165 *     InputStream in = new BufferedInputStream(urlConnection.getInputStream());
166 *     if (!url.getHost().equals(urlConnection.getURL().getHost())) {
167 *       // we were redirected! Kick the user out to the browser to sign on?
168 *     }
169 *     ...
170 *   } finally {
171 *     urlConnection.disconnect();
172 *   }
173 * }</pre>
174 *
175 * <h3>HTTP Authentication</h3>
176 * {@code HttpURLConnection} supports <a
177 * href="http://www.ietf.org/rfc/rfc2617">HTTP basic authentication</a>. Use
178 * {@link Authenticator} to set the VM-wide authentication handler:
179 * <pre>   {@code
180 *   Authenticator.setDefault(new Authenticator() {
181 *     protected PasswordAuthentication getPasswordAuthentication() {
182 *       return new PasswordAuthentication(username, password.toCharArray());
183 *     }
184 *   });
185 * }</pre>
186 * Unless paired with HTTPS, this is <strong>not</strong> a secure mechanism for
187 * user authentication. In particular, the username, password, request and
188 * response are all transmitted over the network without encryption.
189 *
190 * <h3>Sessions with Cookies</h3>
191 * To establish and maintain a potentially long-lived session between client
192 * and server, {@code HttpURLConnection} includes an extensible cookie manager.
193 * Enable VM-wide cookie management using {@link CookieHandler} and {@link
194 * CookieManager}: <pre>   {@code
195 *   CookieManager cookieManager = new CookieManager();
196 *   CookieHandler.setDefault(cookieManager);
197 * }</pre>
198 * By default, {@code CookieManager} accepts cookies from the <a
199 * href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec1.html">origin
200 * server</a> only. Two other policies are included: {@link
201 * CookiePolicy#ACCEPT_ALL} and {@link CookiePolicy#ACCEPT_NONE}. Implement
202 * {@link CookiePolicy} to define a custom policy.
203 *
204 * <p>The default {@code CookieManager} keeps all accepted cookies in memory. It
205 * will forget these cookies when the VM exits. Implement {@link CookieStore} to
206 * define a custom cookie store.
207 *
208 * <p>In addition to the cookies set by HTTP responses, you may set cookies
209 * programmatically. To be included in HTTP request headers, cookies must have
210 * the domain and path properties set.
211 *
212 * <p>By default, new instances of {@code HttpCookie} work only with servers
213 * that support <a href="http://www.ietf.org/rfc/rfc2965.txt">RFC 2965</a>
214 * cookies. Many web servers support only the older specification, <a
215 * href="http://www.ietf.org/rfc/rfc2109.txt">RFC 2109</a>. For compatibility
216 * with the most web servers, set the cookie version to 0.
217 *
218 * <p>For example, to receive {@code www.twitter.com} in French: <pre>   {@code
219 *   HttpCookie cookie = new HttpCookie("lang", "fr");
220 *   cookie.setDomain("twitter.com");
221 *   cookie.setPath("/");
222 *   cookie.setVersion(0);
223 *   cookieManager.getCookieStore().add(new URI("http://twitter.com/"), cookie);
224 * }</pre>
225 *
226 * <h3>HTTP Methods</h3>
227 * <p>{@code HttpURLConnection} uses the {@code GET} method by default. It will
228 * use {@code POST} if {@link #setDoOutput setDoOutput(true)} has been called.
229 * Other HTTP methods ({@code OPTIONS}, {@code HEAD}, {@code PUT}, {@code
230 * DELETE} and {@code TRACE}) can be used with {@link #setRequestMethod}.
231 *
232 * <h3>Proxies</h3>
233 * By default, this class will connect directly to the <a
234 * href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec1.html">origin
235 * server</a>. It can also connect via an {@link Proxy.Type#HTTP HTTP} or {@link
236 * Proxy.Type#SOCKS SOCKS} proxy. To use a proxy, use {@link
237 * URL#openConnection(Proxy) URL.openConnection(Proxy)} when creating the
238 * connection.
239 *
240 * <h3>IPv6 Support</h3>
241 * <p>This class includes transparent support for IPv6. For hosts with both IPv4
242 * and IPv6 addresses, it will attempt to connect to each of a host's addresses
243 * until a connection is established.
244 *
245 * <h3>Response Caching</h3>
246 * Android 4.0 (Ice Cream Sandwich, API level 15) includes a response cache. See
247 * {@code android.net.http.HttpResponseCache} for instructions on enabling HTTP
248 * caching in your application.
249 *
250 * <h3>Avoiding Bugs In Earlier Releases</h3>
251 * Prior to Android 2.2 (Froyo), this class had some frustrating bugs. In
252 * particular, calling {@code close()} on a readable {@code InputStream} could
253 * <a href="http://code.google.com/p/android/issues/detail?id=2939">poison the
254 * connection pool</a>. Work around this by disabling connection pooling:
255 * <pre>   {@code
256 * private void disableConnectionReuseIfNecessary() {
257 *   // Work around pre-Froyo bugs in HTTP connection reuse.
258 *   if (Integer.parseInt(Build.VERSION.SDK) < Build.VERSION_CODES.FROYO) {
259 *     System.setProperty("http.keepAlive", "false");
260 *   }
261 * }}</pre>
262 *
263 * <p>Each instance of {@code HttpURLConnection} may be used for one
264 * request/response pair. Instances of this class are not thread safe.
265 */
266public abstract class HttpURLConnection extends URLConnection {
267    private static final int DEFAULT_CHUNK_LENGTH = 1024;
268
269    /**
270     * The subset of HTTP methods that the user may select via {@link
271     * #setRequestMethod(String)}.
272     */
273    private static final String[] PERMITTED_USER_METHODS = {
274            "OPTIONS",
275            "GET",
276            "HEAD",
277            "POST",
278            "PUT",
279            "DELETE",
280            "TRACE"
281            // Note: we don't allow users to specify "CONNECT"
282    };
283
284    /**
285     * The HTTP request method of this {@code HttpURLConnection}. The default
286     * value is {@code "GET"}.
287     */
288    protected String method = "GET";
289
290    /**
291     * The status code of the response obtained from the HTTP request. The
292     * default value is {@code -1}.
293     * <p>
294     * <li>1xx: Informational</li>
295     * <li>2xx: Success</li>
296     * <li>3xx: Relocation/Redirection</li>
297     * <li>4xx: Client Error</li>
298     * <li>5xx: Server Error</li>
299     */
300    protected int responseCode = -1;
301
302    /**
303     * The HTTP response message which corresponds to the response code.
304     */
305    protected String responseMessage;
306
307    /**
308     * Flag to define whether the protocol will automatically follow redirects
309     * or not. The default value is {@code true}.
310     */
311    protected boolean instanceFollowRedirects = followRedirects;
312
313    private static boolean followRedirects = true;
314
315    /**
316     * If the HTTP chunked encoding is enabled this parameter defines the
317     * chunk-length. Default value is {@code -1} that means the chunked encoding
318     * mode is disabled.
319     */
320    protected int chunkLength = -1;
321
322    /**
323     * The byte count in the request body if it is both known and streamed; and
324     * -1 otherwise. If the byte count exceeds {@link Integer#MAX_VALUE} (2 GiB)
325     * then the value of this field will be {@link Integer#MAX_VALUE}. In that
326     * case use {@link #fixedContentLengthLong} to access the exact byte count.
327     */
328    protected int fixedContentLength = -1;
329
330    /**
331     * The byte count in the request body if it is both known and streamed; and
332     * -1 otherwise. Prefer this field over the {@code int}-valued {@code
333     * fixedContentLength} on platforms that support both.
334     */
335    protected long fixedContentLengthLong = -1;
336
337    // 2XX: generally "OK"
338    // 3XX: relocation/redirect
339    // 4XX: client error
340    // 5XX: server error
341    /**
342     * Numeric status code, 202: Accepted
343     */
344    public static final int HTTP_ACCEPTED = 202;
345
346    /**
347     * Numeric status code, 502: Bad Gateway
348     */
349    public static final int HTTP_BAD_GATEWAY = 502;
350
351    /**
352     * Numeric status code, 405: Bad Method
353     */
354    public static final int HTTP_BAD_METHOD = 405;
355
356    /**
357     * Numeric status code, 400: Bad Request
358     */
359    public static final int HTTP_BAD_REQUEST = 400;
360
361    /**
362     * Numeric status code, 408: Client Timeout
363     */
364    public static final int HTTP_CLIENT_TIMEOUT = 408;
365
366    /**
367     * Numeric status code, 409: Conflict
368     */
369    public static final int HTTP_CONFLICT = 409;
370
371    /**
372     * Numeric status code, 201: Created
373     */
374    public static final int HTTP_CREATED = 201;
375
376    /**
377     * Numeric status code, 413: Entity too large
378     */
379    public static final int HTTP_ENTITY_TOO_LARGE = 413;
380
381    /**
382     * Numeric status code, 403: Forbidden
383     */
384    public static final int HTTP_FORBIDDEN = 403;
385
386    /**
387     * Numeric status code, 504: Gateway timeout
388     */
389    public static final int HTTP_GATEWAY_TIMEOUT = 504;
390
391    /**
392     * Numeric status code, 410: Gone
393     */
394    public static final int HTTP_GONE = 410;
395
396    /**
397     * Numeric status code, 500: Internal error
398     */
399    public static final int HTTP_INTERNAL_ERROR = 500;
400
401    /**
402     * Numeric status code, 411: Length required
403     */
404    public static final int HTTP_LENGTH_REQUIRED = 411;
405
406    /**
407     * Numeric status code, 301 Moved permanently
408     */
409    public static final int HTTP_MOVED_PERM = 301;
410
411    /**
412     * Numeric status code, 302: Moved temporarily
413     */
414    public static final int HTTP_MOVED_TEMP = 302;
415
416    /**
417     * Numeric status code, 300: Multiple choices
418     */
419    public static final int HTTP_MULT_CHOICE = 300;
420
421    /**
422     * Numeric status code, 204: No content
423     */
424    public static final int HTTP_NO_CONTENT = 204;
425
426    /**
427     * Numeric status code, 406: Not acceptable
428     */
429    public static final int HTTP_NOT_ACCEPTABLE = 406;
430
431    /**
432     * Numeric status code, 203: Not authoritative
433     */
434    public static final int HTTP_NOT_AUTHORITATIVE = 203;
435
436    /**
437     * Numeric status code, 404: Not found
438     */
439    public static final int HTTP_NOT_FOUND = 404;
440
441    /**
442     * Numeric status code, 501: Not implemented
443     */
444    public static final int HTTP_NOT_IMPLEMENTED = 501;
445
446    /**
447     * Numeric status code, 304: Not modified
448     */
449    public static final int HTTP_NOT_MODIFIED = 304;
450
451    /**
452     * Numeric status code, 200: OK
453     */
454    public static final int HTTP_OK = 200;
455
456    /**
457     * Numeric status code, 206: Partial
458     */
459    public static final int HTTP_PARTIAL = 206;
460
461    /**
462     * Numeric status code, 402: Payment required
463     */
464    public static final int HTTP_PAYMENT_REQUIRED = 402;
465
466    /**
467     * Numeric status code, 412: Precondition failed
468     */
469    public static final int HTTP_PRECON_FAILED = 412;
470
471    /**
472     * Numeric status code, 407: Proxy authentication required
473     */
474    public static final int HTTP_PROXY_AUTH = 407;
475
476    /**
477     * Numeric status code, 414: Request too long
478     */
479    public static final int HTTP_REQ_TOO_LONG = 414;
480
481    /**
482     * Numeric status code, 205: Reset
483     */
484    public static final int HTTP_RESET = 205;
485
486    /**
487     * Numeric status code, 303: See other
488     */
489    public static final int HTTP_SEE_OTHER = 303;
490
491    /**
492     * Numeric status code, 500: Internal error
493     *
494     * @deprecated Use {@link #HTTP_INTERNAL_ERROR} instead.
495     */
496    @Deprecated
497    public static final int HTTP_SERVER_ERROR = 500;
498
499    /**
500     * Numeric status code, 305: Use proxy.
501     *
502     * <p>Like Firefox and Chrome, this class doesn't honor this response code.
503     * Other implementations respond to this status code by retrying the request
504     * using the HTTP proxy named by the response's Location header field.
505     */
506    public static final int HTTP_USE_PROXY = 305;
507
508    /**
509     * Numeric status code, 401: Unauthorized
510     */
511    public static final int HTTP_UNAUTHORIZED = 401;
512
513    /**
514     * Numeric status code, 415: Unsupported type
515     */
516    public static final int HTTP_UNSUPPORTED_TYPE = 415;
517
518    /**
519     * Numeric status code, 503: Unavailable
520     */
521    public static final int HTTP_UNAVAILABLE = 503;
522
523    /**
524     * Numeric status code, 505: Version not supported
525     */
526    public static final int HTTP_VERSION = 505;
527
528    /**
529     * Constructs a new {@code HttpURLConnection} instance pointing to the
530     * resource specified by the {@code url}.
531     *
532     * @param url
533     *            the URL of this connection.
534     * @see URL
535     * @see URLConnection
536     */
537    protected HttpURLConnection(URL url) {
538        super(url);
539    }
540
541    /**
542     * Releases this connection so that its resources may be either reused or
543     * closed.
544     *
545     * <p>Unlike other Java implementations, this will not necessarily close
546     * socket connections that can be reused. You can disable all connection
547     * reuse by setting the {@code http.keepAlive} system property to {@code
548     * false} before issuing any HTTP requests.
549     */
550    public abstract void disconnect();
551
552    /**
553     * Returns an input stream from the server in the case of an error such as
554     * the requested file has not been found on the remote server. This stream
555     * can be used to read the data the server will send back.
556     *
557     * @return the error input stream returned by the server.
558     */
559    public InputStream getErrorStream() {
560        return null;
561    }
562
563    /**
564     * Returns the value of {@code followRedirects} which indicates if this
565     * connection follows a different URL redirected by the server. It is
566     * enabled by default.
567     *
568     * @return the value of the flag.
569     * @see #setFollowRedirects
570     */
571    public static boolean getFollowRedirects() {
572        return followRedirects;
573    }
574
575    /**
576     * Returns the permission object (in this case {@code SocketPermission})
577     * with the host and the port number as the target name and {@code
578     * "resolve, connect"} as the action list. If the port number of this URL
579     * instance is lower than {@code 0} the port will be set to {@code 80}.
580     *
581     * @return the permission object required for this connection.
582     * @throws IOException
583     *             if an IO exception occurs during the creation of the
584     *             permission object.
585     */
586    @Override
587    public java.security.Permission getPermission() throws IOException {
588        int port = url.getPort();
589        if (port < 0) {
590            port = 80;
591        }
592        return new SocketPermission(url.getHost() + ":" + port,
593                "connect, resolve");
594    }
595
596    /**
597     * Returns the request method which will be used to make the request to the
598     * remote HTTP server. All possible methods of this HTTP implementation is
599     * listed in the class definition.
600     *
601     * @return the request method string.
602     * @see #method
603     * @see #setRequestMethod
604     */
605    public String getRequestMethod() {
606        return method;
607    }
608
609    /**
610     * Returns the response code returned by the remote HTTP server.
611     *
612     * @return the response code, -1 if no valid response code.
613     * @throws IOException
614     *             if there is an IO error during the retrieval.
615     * @see #getResponseMessage
616     */
617    public int getResponseCode() throws IOException {
618        // Call getInputStream() first since getHeaderField() doesn't return
619        // exceptions
620        getInputStream();
621        String response = getHeaderField(0);
622        if (response == null) {
623            return -1;
624        }
625        response = response.trim();
626        int mark = response.indexOf(" ") + 1;
627        if (mark == 0) {
628            return -1;
629        }
630        int last = mark + 3;
631        if (last > response.length()) {
632            last = response.length();
633        }
634        responseCode = Integer.parseInt(response.substring(mark, last));
635        if (last + 1 <= response.length()) {
636            responseMessage = response.substring(last + 1);
637        }
638        return responseCode;
639    }
640
641    /**
642     * Returns the response message returned by the remote HTTP server.
643     *
644     * @return the response message. {@code null} if no such response exists.
645     * @throws IOException
646     *             if there is an error during the retrieval.
647     * @see #getResponseCode()
648     */
649    public String getResponseMessage() throws IOException {
650        if (responseMessage != null) {
651            return responseMessage;
652        }
653        getResponseCode();
654        return responseMessage;
655    }
656
657    /**
658     * Sets the flag of whether this connection will follow redirects returned
659     * by the remote server.
660     *
661     * @param auto
662     *            the value to enable or disable this option.
663     */
664    public static void setFollowRedirects(boolean auto) {
665        followRedirects = auto;
666    }
667
668    /**
669     * Sets the request command which will be sent to the remote HTTP server.
670     * This method can only be called before the connection is made.
671     *
672     * @param method
673     *            the string representing the method to be used.
674     * @throws ProtocolException
675     *             if this is called after connected, or the method is not
676     *             supported by this HTTP implementation.
677     * @see #getRequestMethod()
678     * @see #method
679     */
680    public void setRequestMethod(String method) throws ProtocolException {
681        if (connected) {
682            throw new ProtocolException("Connection already established");
683        }
684        for (String permittedUserMethod : PERMITTED_USER_METHODS) {
685            if (permittedUserMethod.equals(method)) {
686                // if there is a supported method that matches the desired
687                // method, then set the current method and return
688                this.method = permittedUserMethod;
689                return;
690            }
691        }
692        // if none matches, then throw ProtocolException
693        throw new ProtocolException("Unknown method '" + method + "'; must be one of " +
694                Arrays.toString(PERMITTED_USER_METHODS));
695    }
696
697    /**
698     * Returns whether this connection uses a proxy server or not.
699     *
700     * @return {@code true} if this connection passes a proxy server, false
701     *         otherwise.
702     */
703    public abstract boolean usingProxy();
704
705    /**
706     * Returns the encoding used to transmit the response body over the network.
707     * This is null or "identity" if the content was not encoded, or "gzip" if
708     * the body was gzip compressed. Most callers will be more interested in the
709     * {@link #getContentType() content type}, which may also include the
710     * content's character encoding.
711     */
712    @Override public String getContentEncoding() {
713        return super.getContentEncoding(); // overridden for Javadoc only
714    }
715
716    /**
717     * Returns whether this connection follows redirects.
718     *
719     * @return {@code true} if this connection follows redirects, false
720     *         otherwise.
721     */
722    public boolean getInstanceFollowRedirects() {
723        return instanceFollowRedirects;
724    }
725
726    /**
727     * Sets whether this connection follows redirects.
728     *
729     * @param followRedirects
730     *            {@code true} if this connection will follows redirects, false
731     *            otherwise.
732     */
733    public void setInstanceFollowRedirects(boolean followRedirects) {
734        instanceFollowRedirects = followRedirects;
735    }
736
737    /**
738     * Returns the date value in milliseconds since {@code 01.01.1970, 00:00h}
739     * corresponding to the header field {@code field}. The {@code defaultValue}
740     * will be returned if no such field can be found in the response header.
741     *
742     * @param field
743     *            the header field name.
744     * @param defaultValue
745     *            the default value to use if the specified header field wont be
746     *            found.
747     * @return the header field represented in milliseconds since January 1,
748     *         1970 GMT.
749     */
750    @Override
751    public long getHeaderFieldDate(String field, long defaultValue) {
752        return super.getHeaderFieldDate(field, defaultValue);
753    }
754
755    /**
756     * Configures this connection to stream the request body with the known
757     * fixed byte count of {@code contentLength}.
758     *
759     * @see #setChunkedStreamingMode
760     * @param contentLength
761     *            the fixed length of the HTTP request body.
762     * @throws IllegalStateException
763     *             if already connected or another mode already set.
764     * @throws IllegalArgumentException
765     *             if {@code contentLength} is less than zero.
766     * @since 1.7
767     */
768    public void setFixedLengthStreamingMode(long contentLength) {
769        if (super.connected) {
770            throw new IllegalStateException("Already connected");
771        }
772        if (chunkLength > 0) {
773            throw new IllegalStateException("Already in chunked mode");
774        }
775        if (contentLength < 0) {
776            throw new IllegalArgumentException("contentLength < 0");
777        }
778        this.fixedContentLength = (int) Math.min(contentLength, Integer.MAX_VALUE);
779        this.fixedContentLengthLong = contentLength;
780    }
781
782    /**
783     * Equivalent to {@code setFixedLengthStreamingMode((long) contentLength)},
784     * but available on earlier versions of Android and limited to 2 GiB.
785     */
786    public void setFixedLengthStreamingMode(int contentLength) {
787      setFixedLengthStreamingMode((long) contentLength);
788    }
789
790    /**
791     * Stream a request body whose length is not known in advance. Old HTTP/1.0
792     * only servers may not support this mode.
793     *
794     * <p>When HTTP chunked encoding is used, the stream is divided into
795     * chunks, each prefixed with a header containing the chunk's size.
796     * A large chunk length requires a large internal buffer, potentially
797     * wasting memory. A small chunk length increases the number of
798     * bytes that must be transmitted because of the header on every chunk.
799     *
800     * <p>Implementation details: In some releases the {@code chunkLength} is
801     * treated as a hint: chunks sent to the server may actually be larger or
802     * smaller. To force a chunk to be sent to the server call
803     * {@link java.io.OutputStream#flush()}.
804     *
805     * @see #setFixedLengthStreamingMode
806     * @param chunkLength the length to use, or {@code 0} for the default chunk
807     *     length.
808     * @throws IllegalStateException if already connected or another mode
809     *     already set.
810     */
811    public void setChunkedStreamingMode(int chunkLength) {
812        if (super.connected) {
813            throw new IllegalStateException("Already connected");
814        }
815        if (fixedContentLength >= 0) {
816            throw new IllegalStateException("Already in fixed-length mode");
817        }
818        if (chunkLength <= 0) {
819            this.chunkLength = DEFAULT_CHUNK_LENGTH;
820        } else {
821            this.chunkLength = chunkLength;
822        }
823    }
824}
825