HttpEngine.java revision 7407d6984ce69693097befc9b72609a8156463bb
1c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath/*
2c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath *  Licensed to the Apache Software Foundation (ASF) under one or more
3c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath *  contributor license agreements.  See the NOTICE file distributed with
4c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath *  this work for additional information regarding copyright ownership.
5c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath *  The ASF licenses this file to You under the Apache License, Version 2.0
6c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath *  (the "License"); you may not use this file except in compliance with
7c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath *  the License.  You may obtain a copy of the License at
8c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath *
9c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath *     http://www.apache.org/licenses/LICENSE-2.0
10c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath *
11c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath *  Unless required by applicable law or agreed to in writing, software
12c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath *  distributed under the License is distributed on an "AS IS" BASIS,
13c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath *  See the License for the specific language governing permissions and
15c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath *  limitations under the License.
16c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath */
17c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath
182231db3e6bb54447a9b14cf004a6cb03c373651cjwilsonpackage com.squareup.okhttp.internal.http;
192231db3e6bb54447a9b14cf004a6cb03c373651cjwilson
202231db3e6bb54447a9b14cf004a6cb03c373651cjwilsonimport com.squareup.okhttp.Address;
212231db3e6bb54447a9b14cf004a6cb03c373651cjwilsonimport com.squareup.okhttp.Connection;
222231db3e6bb54447a9b14cf004a6cb03c373651cjwilsonimport com.squareup.okhttp.OkResponseCache;
232231db3e6bb54447a9b14cf004a6cb03c373651cjwilsonimport com.squareup.okhttp.ResponseSource;
242231db3e6bb54447a9b14cf004a6cb03c373651cjwilsonimport com.squareup.okhttp.TunnelRequest;
2554cf3446000fdcf88a9e62724f7deb0282e98da1jwilsonimport com.squareup.okhttp.internal.Dns;
262231db3e6bb54447a9b14cf004a6cb03c373651cjwilsonimport com.squareup.okhttp.internal.Platform;
272231db3e6bb54447a9b14cf004a6cb03c373651cjwilsonimport com.squareup.okhttp.internal.Util;
28c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamathimport java.io.ByteArrayInputStream;
29c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamathimport java.io.IOException;
30c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamathimport java.io.InputStream;
31c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamathimport java.io.OutputStream;
32c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamathimport java.net.CacheRequest;
33c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamathimport java.net.CacheResponse;
34c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamathimport java.net.CookieHandler;
35c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamathimport java.net.Proxy;
36c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamathimport java.net.URI;
37c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamathimport java.net.URISyntaxException;
38c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamathimport java.net.URL;
392231db3e6bb54447a9b14cf004a6cb03c373651cjwilsonimport java.net.UnknownHostException;
40c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamathimport java.util.Collections;
41c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamathimport java.util.Date;
42c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamathimport java.util.HashMap;
43c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamathimport java.util.List;
44c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamathimport java.util.Map;
45c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamathimport java.util.zip.GZIPInputStream;
467899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamathimport javax.net.ssl.HostnameVerifier;
47c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamathimport javax.net.ssl.SSLSocketFactory;
48c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath
4954cf3446000fdcf88a9e62724f7deb0282e98da1jwilsonimport static com.squareup.okhttp.internal.Util.EMPTY_BYTE_ARRAY;
5054cf3446000fdcf88a9e62724f7deb0282e98da1jwilsonimport static com.squareup.okhttp.internal.Util.getDefaultPort;
5154cf3446000fdcf88a9e62724f7deb0282e98da1jwilsonimport static com.squareup.okhttp.internal.Util.getEffectivePort;
5254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
53c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath/**
54c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath * Handles a single HTTP request/response pair. Each HTTP engine follows this
55c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath * lifecycle:
56c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath * <ol>
5754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson * <li>It is created.
5854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson * <li>The HTTP request message is sent with sendRequest(). Once the request
5954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson * is sent it is an error to modify the request headers. After
6054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson * sendRequest() has been called the request body can be written to if
6154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson * it exists.
6254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson * <li>The HTTP response message is read with readResponse(). After the
6354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson * response has been read the response headers and body can be read.
6454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson * All responses have a response body input stream, though in some
6554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson * instances this stream is empty.
66c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath * </ol>
67c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath *
68c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath * <p>The request and response may be served by the HTTP response cache, by the
69c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath * network, or by both in the event of a conditional GET.
70c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath *
71c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath * <p>This class may hold a socket connection that needs to be released or
72c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath * recycled. By default, this socket connection is held when the last byte of
73c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath * the response is consumed. To release the connection when it is no longer
74c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath * required, use {@link #automaticallyReleaseConnectionToPool()}.
75c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath */
76c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamathpublic class HttpEngine {
7754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  private static final CacheResponse GATEWAY_TIMEOUT_RESPONSE = new CacheResponse() {
7854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    @Override public Map<String, List<String>> getHeaders() throws IOException {
7954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      Map<String, List<String>> result = new HashMap<String, List<String>>();
8054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      result.put(null, Collections.singletonList("HTTP/1.1 504 Gateway Timeout"));
8154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      return result;
82c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath    }
8354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    @Override public InputStream getBody() throws IOException {
8454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      return new ByteArrayInputStream(EMPTY_BYTE_ARRAY);
85c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath    }
8654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  };
8754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  public static final int HTTP_CONTINUE = 100;
8854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
8954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  protected final HttpURLConnectionImpl policy;
9054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
9154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  protected final String method;
9254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
9354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  private ResponseSource responseSource;
9454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
9554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  protected Connection connection;
9654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  protected RouteSelector routeSelector;
9754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  private OutputStream requestBodyOut;
9854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
9954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  private Transport transport;
10054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
10154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  private InputStream responseTransferIn;
10254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  private InputStream responseBodyIn;
10354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
10454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  private CacheResponse cacheResponse;
10554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  private CacheRequest cacheRequest;
10654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
10754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  /** The time when the request headers were written, or -1 if they haven't been written yet. */
10854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  long sentRequestMillis = -1;
10954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
11054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  /**
11154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson   * True if this client added an "Accept-Encoding: gzip" header field and is
11254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson   * therefore responsible for also decompressing the transfer stream.
11354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson   */
11454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  private boolean transparentGzip;
11554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
11654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  final URI uri;
11754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
11854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  final RequestHeaders requestHeaders;
11954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
12054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  /** Null until a response is received from the network or the cache. */
12154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  ResponseHeaders responseHeaders;
12254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
12354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  // The cache response currently being validated on a conditional get. Null
12454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  // if the cached response doesn't exist or doesn't need validation. If the
12554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  // conditional get succeeds, these will be used for the response headers and
12654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  // body. If it fails, these be closed and set to null.
12754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  private ResponseHeaders cachedResponseHeaders;
12854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  private InputStream cachedResponseBody;
12954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
13054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  /**
13154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson   * True if the socket connection should be released to the connection pool
13254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson   * when the response has been fully read.
13354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson   */
13454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  private boolean automaticallyReleaseConnectionToPool;
13554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
13654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  /** True if the socket connection is no longer needed by this engine. */
13754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  private boolean connectionReleased;
13854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
13954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  /**
14054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson   * @param requestHeaders the client's supplied request headers. This class
14154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson   * creates a private copy that it can mutate.
14254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson   * @param connection the connection used for an intermediate response
14354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson   * immediately prior to this request/response pair, such as a same-host
14454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson   * redirect. This engine assumes ownership of the connection and must
14554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson   * release it when it is unneeded.
14654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson   */
14754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  public HttpEngine(HttpURLConnectionImpl policy, String method, RawHeaders requestHeaders,
14854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      Connection connection, RetryableOutputStream requestBodyOut) throws IOException {
14954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    this.policy = policy;
15054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    this.method = method;
15154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    this.connection = connection;
15254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    this.requestBodyOut = requestBodyOut;
15354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
15454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    try {
15554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      uri = Platform.get().toUriLenient(policy.getURL());
15654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    } catch (URISyntaxException e) {
15754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      throw new IOException(e);
15854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    }
15954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
16054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    this.requestHeaders = new RequestHeaders(uri, new RawHeaders(requestHeaders));
16154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
16254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
16354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  public URI getUri() {
16454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    return uri;
16554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
16654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
16754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  /**
16854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson   * Figures out what the response source will be, and opens a socket to that
16954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson   * source if necessary. Prepares the request headers and gets ready to start
17054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson   * writing the request body if it exists.
17154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson   */
17254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  public final void sendRequest() throws IOException {
17354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    if (responseSource != null) {
17454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      return;
17554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    }
17654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
17754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    prepareRawRequestHeaders();
17854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    initResponseSource();
17954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    if (policy.responseCache instanceof OkResponseCache) {
18054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      ((OkResponseCache) policy.responseCache).trackResponse(responseSource);
18154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    }
18254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
18354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    // The raw response source may require the network, but the request
18454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    // headers may forbid network use. In that case, dispose of the network
18554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    // response and use a GATEWAY_TIMEOUT response instead, as specified
18654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    // by http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.9.4.
18754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    if (requestHeaders.isOnlyIfCached() && responseSource.requiresConnection()) {
18854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      if (responseSource == ResponseSource.CONDITIONAL_CACHE) {
18954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson        Util.closeQuietly(cachedResponseBody);
19054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      }
19154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      this.responseSource = ResponseSource.CACHE;
19254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      this.cacheResponse = GATEWAY_TIMEOUT_RESPONSE;
19354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      RawHeaders rawResponseHeaders = RawHeaders.fromMultimap(cacheResponse.getHeaders(), true);
19454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      setResponse(new ResponseHeaders(uri, rawResponseHeaders), cacheResponse.getBody());
19554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    }
19654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
19754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    if (responseSource.requiresConnection()) {
19854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      sendSocketRequest();
19954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    } else if (connection != null) {
20054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      policy.connectionPool.recycle(connection);
20154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      connection = null;
20254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    }
20354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
20454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
20554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  /**
20654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson   * Initialize the source for this response. It may be corrected later if the
20754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson   * request headers forbids network use.
20854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson   */
20954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  private void initResponseSource() throws IOException {
21054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    responseSource = ResponseSource.NETWORK;
21154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    if (!policy.getUseCaches() || policy.responseCache == null) {
21254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      return;
21354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    }
21454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
21554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    CacheResponse candidate =
21654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson        policy.responseCache.get(uri, method, requestHeaders.getHeaders().toMultimap(false));
21754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    if (candidate == null) {
21854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      return;
21954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    }
22054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
22154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    Map<String, List<String>> responseHeadersMap = candidate.getHeaders();
22254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    cachedResponseBody = candidate.getBody();
22354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    if (!acceptCacheResponseType(candidate)
22454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson        || responseHeadersMap == null
22554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson        || cachedResponseBody == null) {
22654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      Util.closeQuietly(cachedResponseBody);
22754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      return;
22854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    }
22954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
23054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    RawHeaders rawResponseHeaders = RawHeaders.fromMultimap(responseHeadersMap, true);
23154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    cachedResponseHeaders = new ResponseHeaders(uri, rawResponseHeaders);
23254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    long now = System.currentTimeMillis();
23354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    this.responseSource = cachedResponseHeaders.chooseResponseSource(now, requestHeaders);
23454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    if (responseSource == ResponseSource.CACHE) {
23554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      this.cacheResponse = candidate;
23654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      setResponse(cachedResponseHeaders, cachedResponseBody);
23754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    } else if (responseSource == ResponseSource.CONDITIONAL_CACHE) {
23854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      this.cacheResponse = candidate;
23954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    } else if (responseSource == ResponseSource.NETWORK) {
24054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      Util.closeQuietly(cachedResponseBody);
24154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    } else {
24254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      throw new AssertionError();
24354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    }
24454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
24554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
24654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  private void sendSocketRequest() throws IOException {
24754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    if (connection == null) {
24854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      connect();
24954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    }
25054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
25154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    if (transport != null) {
25254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      throw new IllegalStateException();
25354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    }
25454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
25554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    transport = (Transport) connection.newTransport(this);
25654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
25754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    if (hasRequestBody() && requestBodyOut == null) {
25854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      // Create a request body if we don't have one already. We'll already
25954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      // have one if we're retrying a failed POST.
26054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      requestBodyOut = transport.createRequestBody();
26154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    }
26254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
26354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
26454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  /** Connect to the origin server either directly or via a proxy. */
26554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  protected final void connect() throws IOException {
26654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    if (connection != null) {
26754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      return;
26854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    }
26954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    if (routeSelector == null) {
27054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      String uriHost = uri.getHost();
27154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      if (uriHost == null) {
27254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson        throw new UnknownHostException(uri.toString());
27354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      }
2747407d6984ce69693097befc9b72609a8156463bbNarayan Kamath      SSLSocketFactory sslSocketFactory = null;
2757407d6984ce69693097befc9b72609a8156463bbNarayan Kamath      HostnameVerifier hostnameVerifier = null;
2767407d6984ce69693097befc9b72609a8156463bbNarayan Kamath      if (uri.getScheme().equalsIgnoreCase("https")) {
2777407d6984ce69693097befc9b72609a8156463bbNarayan Kamath        sslSocketFactory = policy.sslSocketFactory;
2787407d6984ce69693097befc9b72609a8156463bbNarayan Kamath        hostnameVerifier = policy.hostnameVerifier;
2797407d6984ce69693097befc9b72609a8156463bbNarayan Kamath      }
2807407d6984ce69693097befc9b72609a8156463bbNarayan Kamath      Address address = new Address(uriHost, getEffectivePort(uri), sslSocketFactory,
2817407d6984ce69693097befc9b72609a8156463bbNarayan Kamath          hostnameVerifier, policy.requestedProxy);
28254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      routeSelector =
28354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson          new RouteSelector(address, uri, policy.proxySelector, policy.connectionPool, Dns.DEFAULT);
28454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    }
28554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    connection = routeSelector.next();
28654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    if (!connection.isConnected()) {
28754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      connection.connect(policy.getConnectTimeout(), policy.getReadTimeout(), getTunnelConfig());
28854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      policy.connectionPool.maybeShare(connection);
28954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    }
29054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    connected(connection);
2917407d6984ce69693097befc9b72609a8156463bbNarayan Kamath    if (connection.getProxy() != policy.requestedProxy) {
2927407d6984ce69693097befc9b72609a8156463bbNarayan Kamath      // Update the request line if the proxy changed; it may need a host name.
29354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      requestHeaders.getHeaders().setRequestLine(getRequestLine());
29454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    }
29554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
29654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
29754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  /**
29854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson   * Called after a socket connection has been created or retrieved from the
29954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson   * pool. Subclasses use this hook to get a reference to the TLS data.
30054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson   */
30154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  protected void connected(Connection connection) {
30254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
30354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
30454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  /**
30554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson   * Called immediately before the transport transmits HTTP request headers.
30654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson   * This is used to observe the sent time should the request be cached.
30754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson   */
30854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  public void writingRequestHeaders() {
30954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    if (sentRequestMillis != -1) {
31054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      throw new IllegalStateException();
31154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    }
31254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    sentRequestMillis = System.currentTimeMillis();
31354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
31454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
31554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  /**
31654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson   * @param body the response body, or null if it doesn't exist or isn't
31754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson   * available.
31854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson   */
31954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  private void setResponse(ResponseHeaders headers, InputStream body) throws IOException {
32054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    if (this.responseBodyIn != null) {
32154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      throw new IllegalStateException();
32254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    }
32354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    this.responseHeaders = headers;
32454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    if (body != null) {
32554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      initContentStream(body);
32654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    }
32754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
32854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
32954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  boolean hasRequestBody() {
33054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    return method.equals("POST") || method.equals("PUT");
33154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
33254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
33354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  /** Returns the request body or null if this request doesn't have a body. */
33454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  public final OutputStream getRequestBody() {
33554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    if (responseSource == null) {
33654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      throw new IllegalStateException();
33754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    }
33854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    return requestBodyOut;
33954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
34054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
34154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  public final boolean hasResponse() {
34254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    return responseHeaders != null;
34354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
34454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
34554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  public final RequestHeaders getRequestHeaders() {
34654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    return requestHeaders;
34754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
34854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
34954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  public final ResponseHeaders getResponseHeaders() {
35054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    if (responseHeaders == null) {
35154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      throw new IllegalStateException();
35254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    }
35354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    return responseHeaders;
35454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
35554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
35654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  public final int getResponseCode() {
35754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    if (responseHeaders == null) {
35854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      throw new IllegalStateException();
35954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    }
36054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    return responseHeaders.getHeaders().getResponseCode();
36154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
36254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
36354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  public final InputStream getResponseBody() {
36454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    if (responseHeaders == null) {
36554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      throw new IllegalStateException();
36654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    }
36754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    return responseBodyIn;
36854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
36954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
37054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  public final CacheResponse getCacheResponse() {
37154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    return cacheResponse;
37254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
37354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
37454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  public final Connection getConnection() {
37554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    return connection;
37654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
37754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
37854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  /**
37954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson   * Returns true if {@code cacheResponse} is of the right type. This
38054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson   * condition is necessary but not sufficient for the cached response to
38154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson   * be used.
38254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson   */
38354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  protected boolean acceptCacheResponseType(CacheResponse cacheResponse) {
38454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    return true;
38554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
38654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
38754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  private void maybeCache() throws IOException {
38854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    // Are we caching at all?
38954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    if (!policy.getUseCaches() || policy.responseCache == null) {
39054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      return;
39154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    }
39254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
39354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    // Should we cache this response for this request?
39454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    if (!responseHeaders.isCacheable(requestHeaders)) {
39554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      return;
39654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    }
39754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
39854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    // Offer this request to the cache.
3997407d6984ce69693097befc9b72609a8156463bbNarayan Kamath    cacheRequest = policy.responseCache.put(uri, policy.getHttpConnectionToCache());
40054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
40154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
40254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  /**
40354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson   * Cause the socket connection to be released to the connection pool when
40454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson   * it is no longer needed. If it is already unneeded, it will be pooled
40554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson   * immediately. Otherwise the connection is held so that redirects can be
40654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson   * handled by the same connection.
40754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson   */
40854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  public final void automaticallyReleaseConnectionToPool() {
40954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    automaticallyReleaseConnectionToPool = true;
41054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    if (connection != null && connectionReleased) {
41154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      policy.connectionPool.recycle(connection);
41254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      connection = null;
41354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    }
41454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
41554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
41654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  /**
41754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson   * Releases this engine so that its resources may be either reused or
41854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson   * closed. Also call {@link #automaticallyReleaseConnectionToPool} unless
41954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson   * the connection will be used to follow a redirect.
42054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson   */
42154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  public final void release(boolean streamCancelled) {
42254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    // If the response body comes from the cache, close it.
42354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    if (responseBodyIn == cachedResponseBody) {
42454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      Util.closeQuietly(responseBodyIn);
425c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath    }
426c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath
42754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    if (!connectionReleased && connection != null) {
42854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      connectionReleased = true;
429c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath
43054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      if (transport == null || !transport.makeReusable(streamCancelled, requestBodyOut,
43154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson          responseTransferIn)) {
43254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson        Util.closeQuietly(connection);
43354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson        connection = null;
43454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      } else if (automaticallyReleaseConnectionToPool) {
43554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson        policy.connectionPool.recycle(connection);
43654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson        connection = null;
43754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      }
43854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    }
43954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
440c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath
44154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  private void initContentStream(InputStream transferStream) throws IOException {
44254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    responseTransferIn = transferStream;
44354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    if (transparentGzip && responseHeaders.isContentEncodingGzip()) {
44454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      // If the response was transparently gzipped, remove the gzip header field
44554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      // so clients don't double decompress. http://b/3009828
44654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      //
44754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      // Also remove the Content-Length in this case because it contains the
44854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      // length 528 of the gzipped response. This isn't terribly useful and is
44954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      // dangerous because 529 clients can query the content length, but not
45054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      // the content encoding.
45154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      responseHeaders.stripContentEncoding();
45254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      responseHeaders.stripContentLength();
45354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      responseBodyIn = new GZIPInputStream(transferStream);
45454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    } else {
45554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      responseBodyIn = transferStream;
45654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    }
45754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
45854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
45954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  /**
46054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson   * Returns true if the response must have a (possibly 0-length) body.
46154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson   * See RFC 2616 section 4.3.
46254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson   */
46354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  public final boolean hasResponseBody() {
46454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    int responseCode = responseHeaders.getHeaders().getResponseCode();
46554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
46654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    // HEAD requests never yield a body regardless of the response headers.
46754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    if (method.equals("HEAD")) {
46854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      return false;
46954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    }
47054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
47154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    if ((responseCode < HTTP_CONTINUE || responseCode >= 200)
47254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson        && responseCode != HttpURLConnectionImpl.HTTP_NO_CONTENT
47354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson        && responseCode != HttpURLConnectionImpl.HTTP_NOT_MODIFIED) {
47454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      return true;
47554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    }
47654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
47754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    // If the Content-Length or Transfer-Encoding headers disagree with the
47854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    // response code, the response is malformed. For best compatibility, we
47954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    // honor the headers.
48054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    if (responseHeaders.getContentLength() != -1 || responseHeaders.isChunked()) {
48154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      return true;
48254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    }
48354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
48454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    return false;
48554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
48654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
48754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  /**
48854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson   * Populates requestHeaders with defaults and cookies.
48954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson   *
49054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson   * <p>This client doesn't specify a default {@code Accept} header because it
49154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson   * doesn't know what content types the application is interested in.
49254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson   */
49354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  private void prepareRawRequestHeaders() throws IOException {
49454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    requestHeaders.getHeaders().setRequestLine(getRequestLine());
49554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
49654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    if (requestHeaders.getUserAgent() == null) {
49754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      requestHeaders.setUserAgent(getDefaultUserAgent());
49854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    }
49954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
50054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    if (requestHeaders.getHost() == null) {
50154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      requestHeaders.setHost(getOriginAddress(policy.getURL()));
50254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    }
50354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
50454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    if ((connection == null || connection.getHttpMinorVersion() != 0)
50554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson        && requestHeaders.getConnection() == null) {
50654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      requestHeaders.setConnection("Keep-Alive");
50754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    }
50854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
50954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    if (requestHeaders.getAcceptEncoding() == null) {
51054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      transparentGzip = true;
51154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      requestHeaders.setAcceptEncoding("gzip");
51254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    }
51354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
51454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    if (hasRequestBody() && requestHeaders.getContentType() == null) {
51554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      requestHeaders.setContentType("application/x-www-form-urlencoded");
51654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    }
51754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
51854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    long ifModifiedSince = policy.getIfModifiedSince();
51954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    if (ifModifiedSince != 0) {
52054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      requestHeaders.setIfModifiedSince(new Date(ifModifiedSince));
52154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    }
52254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
52354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    CookieHandler cookieHandler = policy.cookieHandler;
52454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    if (cookieHandler != null) {
52554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      requestHeaders.addCookies(
52654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson          cookieHandler.get(uri, requestHeaders.getHeaders().toMultimap(false)));
52754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    }
52854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
52954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
53054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  /**
53154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson   * Returns the request status line, like "GET / HTTP/1.1". This is exposed
53254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson   * to the application by {@link HttpURLConnectionImpl#getHeaderFields}, so
53354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson   * it needs to be set even if the transport is SPDY.
53454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson   */
53554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  String getRequestLine() {
53654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    String protocol =
53754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson        (connection == null || connection.getHttpMinorVersion() != 0) ? "HTTP/1.1" : "HTTP/1.0";
53854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    return method + " " + requestString() + " " + protocol;
53954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
54054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
54154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  private String requestString() {
54254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    URL url = policy.getURL();
54354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    if (includeAuthorityInRequestLine()) {
54454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      return url.toString();
54554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    } else {
54654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      return requestPath(url);
54754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    }
54854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
54954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
55054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  /**
55154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson   * Returns the path to request, like the '/' in 'GET / HTTP/1.1'. Never
55254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson   * empty, even if the request URL is. Includes the query component if it
55354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson   * exists.
55454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson   */
55554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  public static String requestPath(URL url) {
55654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    String fileOnly = url.getFile();
55754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    if (fileOnly == null) {
55854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      return "/";
55954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    } else if (!fileOnly.startsWith("/")) {
56054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      return "/" + fileOnly;
56154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    } else {
56254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      return fileOnly;
563c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath    }
56454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
565c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath
56654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  /**
56754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson   * Returns true if the request line should contain the full URL with host
56854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson   * and port (like "GET http://android.com/foo HTTP/1.1") or only the path
56954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson   * (like "GET /foo HTTP/1.1").
57054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson   *
57154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson   * <p>This is non-final because for HTTPS it's never necessary to supply the
57254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson   * full URL, even if a proxy is in use.
57354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson   */
57454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  protected boolean includeAuthorityInRequestLine() {
5757407d6984ce69693097befc9b72609a8156463bbNarayan Kamath    return connection == null
5767407d6984ce69693097befc9b72609a8156463bbNarayan Kamath        ? policy.usingProxy() // A proxy was requested.
5777407d6984ce69693097befc9b72609a8156463bbNarayan Kamath        : connection.getProxy().type() == Proxy.Type.HTTP; // A proxy was selected.
57854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
57954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
58054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  public static String getDefaultUserAgent() {
58154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    String agent = System.getProperty("http.agent");
58254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    return agent != null ? agent : ("Java" + System.getProperty("java.version"));
58354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
58454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
58554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  public static String getOriginAddress(URL url) {
58654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    int port = url.getPort();
58754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    String result = url.getHost();
58854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    if (port > 0 && port != getDefaultPort(url.getProtocol())) {
58954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      result = result + ":" + port;
59054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    }
59154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    return result;
59254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
59354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
59454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  /**
59554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson   * Flushes the remaining request header and body, parses the HTTP response
59654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson   * headers and starts reading the HTTP response body if it exists.
59754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson   */
59854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  public final void readResponse() throws IOException {
59954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    if (hasResponse()) {
60054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      return;
60154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    }
60254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
60354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    if (responseSource == null) {
60454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      throw new IllegalStateException("readResponse() without sendRequest()");
60554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    }
60654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
60754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    if (!responseSource.requiresConnection()) {
60854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      return;
60954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    }
61054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
61154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    if (sentRequestMillis == -1) {
61254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      if (requestBodyOut instanceof RetryableOutputStream) {
61354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson        int contentLength = ((RetryableOutputStream) requestBodyOut).contentLength();
61454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson        requestHeaders.setContentLength(contentLength);
61554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      }
61654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      transport.writeRequestHeaders();
61754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    }
61854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
61954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    if (requestBodyOut != null) {
62054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      requestBodyOut.close();
62154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      if (requestBodyOut instanceof RetryableOutputStream) {
62254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson        transport.writeRequestBody((RetryableOutputStream) requestBodyOut);
62354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      }
62454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    }
62554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
62654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    transport.flushRequest();
62754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
62854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    responseHeaders = transport.readResponseHeaders();
62954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    responseHeaders.setLocalTimestamps(sentRequestMillis, System.currentTimeMillis());
63054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
63154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    if (responseSource == ResponseSource.CONDITIONAL_CACHE) {
63254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      if (cachedResponseHeaders.validate(responseHeaders)) {
63354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson        release(false);
63454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson        ResponseHeaders combinedHeaders = cachedResponseHeaders.combine(responseHeaders);
63554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson        setResponse(combinedHeaders, cachedResponseBody);
63654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson        if (policy.responseCache instanceof OkResponseCache) {
63754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson          OkResponseCache httpResponseCache = (OkResponseCache) policy.responseCache;
63854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson          httpResponseCache.trackConditionalCacheHit();
6397407d6984ce69693097befc9b72609a8156463bbNarayan Kamath          httpResponseCache.update(cacheResponse, policy.getHttpConnectionToCache());
640c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath        }
64154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson        return;
64254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      } else {
64354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson        Util.closeQuietly(cachedResponseBody);
64454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      }
645c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath    }
646c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath
64754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    if (hasResponseBody()) {
64854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      maybeCache(); // reentrant. this calls into user code which may call back into this!
649c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath    }
650c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath
65154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    initContentStream(transport.getTransferStream(cacheRequest));
65254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
653c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath
65454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  protected TunnelRequest getTunnelConfig() {
65554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    return null;
65654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
6577899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
65854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  public void receiveHeaders(RawHeaders headers) throws IOException {
65954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    CookieHandler cookieHandler = policy.cookieHandler;
66054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    if (cookieHandler != null) {
66154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      cookieHandler.put(uri, headers.toMultimap(true));
6627899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    }
66354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
664c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath}
665