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