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