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