HttpEngine.java revision 7899c5ab935cf542069835ec7d3e457db596dbf7
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
18c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamathpackage libcore.net.http;
19c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath
20c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamathimport com.squareup.okhttp.OkHttpConnection;
21c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamathimport java.io.ByteArrayInputStream;
22c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamathimport java.io.IOException;
23c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamathimport java.io.InputStream;
24c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamathimport java.io.OutputStream;
25c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamathimport java.net.CacheRequest;
26c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamathimport java.net.CacheResponse;
27c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamathimport java.net.CookieHandler;
28c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamathimport java.net.Proxy;
29c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamathimport java.net.ResponseCache;
30c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamathimport java.net.URI;
31c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamathimport java.net.URISyntaxException;
32c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamathimport java.net.URL;
33c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamathimport java.util.Collections;
34c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamathimport java.util.Date;
35c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamathimport java.util.HashMap;
36c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamathimport java.util.List;
37c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamathimport java.util.Map;
38c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamathimport java.util.zip.GZIPInputStream;
397899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamathimport javax.net.ssl.HostnameVerifier;
40c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamathimport javax.net.ssl.SSLSocketFactory;
41c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamathimport libcore.io.IoUtils;
42c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamathimport libcore.util.EmptyArray;
43c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamathimport libcore.util.ExtendedResponseCache;
44c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamathimport libcore.util.Libcore;
45c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamathimport libcore.util.ResponseSource;
46c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath
47c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath/**
48c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath * Handles a single HTTP request/response pair. Each HTTP engine follows this
49c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath * lifecycle:
50c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath * <ol>
51c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath *     <li>It is created.
52c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath *     <li>The HTTP request message is sent with sendRequest(). Once the request
53c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath *         is sent it is an error to modify the request headers. After
54c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath *         sendRequest() has been called the request body can be written to if
55c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath *         it exists.
56c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath *     <li>The HTTP response message is read with readResponse(). After the
57c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath *         response has been read the response headers and body can be read.
58c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath *         All responses have a response body input stream, though in some
59c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath *         instances this stream is empty.
60c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath * </ol>
61c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath *
62c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath * <p>The request and response may be served by the HTTP response cache, by the
63c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath * network, or by both in the event of a conditional GET.
64c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath *
65c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath * <p>This class may hold a socket connection that needs to be released or
66c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath * recycled. By default, this socket connection is held when the last byte of
67c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath * the response is consumed. To release the connection when it is no longer
68c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath * required, use {@link #automaticallyReleaseConnectionToPool()}.
69c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath */
70c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamathpublic class HttpEngine {
717899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    private static final CacheResponse GATEWAY_TIMEOUT_RESPONSE = new CacheResponse() {
72c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath        @Override public Map<String, List<String>> getHeaders() throws IOException {
73c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath            Map<String, List<String>> result = new HashMap<String, List<String>>();
747899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath            result.put(null, Collections.singletonList("HTTP/1.1 504 Gateway Timeout"));
75c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath            return result;
76c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath        }
77c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath        @Override public InputStream getBody() throws IOException {
78c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath            return new ByteArrayInputStream(EmptyArray.BYTE);
79c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath        }
80c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath    };
81c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath    public static final int DEFAULT_CHUNK_LENGTH = 1024;
82c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath
83c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath    public static final String OPTIONS = "OPTIONS";
84c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath    public static final String GET = "GET";
85c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath    public static final String HEAD = "HEAD";
86c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath    public static final String POST = "POST";
87c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath    public static final String PUT = "PUT";
88c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath    public static final String DELETE = "DELETE";
89c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath    public static final String TRACE = "TRACE";
90c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath
91c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath    public static final int HTTP_CONTINUE = 100;
92c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath
93c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath    protected final HttpURLConnectionImpl policy;
94c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath
95c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath    protected final String method;
96c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath
97c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath    private ResponseSource responseSource;
98c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath
99c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath    protected HttpConnection connection;
100c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath    private OutputStream requestBodyOut;
101c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath
102c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath    private Transport transport;
103c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath
1047899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    private InputStream responseTransferIn;
105c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath    private InputStream responseBodyIn;
106c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath
107c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath    private final ResponseCache responseCache = ResponseCache.getDefault();
108c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath    private CacheResponse cacheResponse;
109c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath    private CacheRequest cacheRequest;
110c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath
111c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath    /** The time when the request headers were written, or -1 if they haven't been written yet. */
112c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath    long sentRequestMillis = -1;
113c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath
114c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath    /**
115c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath     * True if this client added an "Accept-Encoding: gzip" header field and is
116c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath     * therefore responsible for also decompressing the transfer stream.
117c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath     */
118c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath    private boolean transparentGzip;
119c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath
120c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath    final URI uri;
121c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath
122c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath    final RequestHeaders requestHeaders;
123c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath
124c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath    /** Null until a response is received from the network or the cache. */
125c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath    ResponseHeaders responseHeaders;
126c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath
127c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath    /*
128c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath     * The cache response currently being validated on a conditional get. Null
129c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath     * if the cached response doesn't exist or doesn't need validation. If the
130c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath     * conditional get succeeds, these will be used for the response headers and
131c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath     * body. If it fails, these be closed and set to null.
132c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath     */
133c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath    private ResponseHeaders cachedResponseHeaders;
134c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath    private InputStream cachedResponseBody;
135c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath
136c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath    /**
137c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath     * True if the socket connection should be released to the connection pool
138c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath     * when the response has been fully read.
139c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath     */
140c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath    private boolean automaticallyReleaseConnectionToPool;
141c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath
142c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath    /** True if the socket connection is no longer needed by this engine. */
143c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath    private boolean connectionReleased;
144c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath
145c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath    /**
146c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath     * @param requestHeaders the client's supplied request headers. This class
147c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath     *     creates a private copy that it can mutate.
148c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath     * @param connection the connection used for an intermediate response
149c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath     *     immediately prior to this request/response pair, such as a same-host
150c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath     *     redirect. This engine assumes ownership of the connection and must
151c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath     *     release it when it is unneeded.
152c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath     */
153c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath    public HttpEngine(HttpURLConnectionImpl policy, String method, RawHeaders requestHeaders,
154c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath            HttpConnection connection, RetryableOutputStream requestBodyOut) throws IOException {
155c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath        this.policy = policy;
156c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath        this.method = method;
157c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath        this.connection = connection;
158c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath        this.requestBodyOut = requestBodyOut;
159c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath
160c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath        try {
161c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath            uri = Libcore.toUriLenient(policy.getURL());
162c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath        } catch (URISyntaxException e) {
163c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath            throw new IOException(e);
164c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath        }
165c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath
166c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath        this.requestHeaders = new RequestHeaders(uri, new RawHeaders(requestHeaders));
167c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath    }
168c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath
169c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath    public URI getUri() {
170c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath        return uri;
171c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath    }
172c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath
173c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath    /**
174c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath     * Figures out what the response source will be, and opens a socket to that
175c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath     * source if necessary. Prepares the request headers and gets ready to start
176c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath     * writing the request body if it exists.
177c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath     */
178c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath    public final void sendRequest() throws IOException {
179c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath        if (responseSource != null) {
180c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath            return;
181c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath        }
182c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath
183c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath        prepareRawRequestHeaders();
184c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath        initResponseSource();
185c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath        if (responseCache instanceof ExtendedResponseCache) {
186c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath            ((ExtendedResponseCache) responseCache).trackResponse(responseSource);
187c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath        }
188c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath
189c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath        /*
190c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath         * The raw response source may require the network, but the request
191c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath         * headers may forbid network use. In that case, dispose of the network
1927899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath         * response and use a GATEWAY_TIMEOUT response instead, as specified
1937899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath         * by http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.9.4.
194c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath         */
195c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath        if (requestHeaders.isOnlyIfCached() && responseSource.requiresConnection()) {
196c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath            if (responseSource == ResponseSource.CONDITIONAL_CACHE) {
197c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath                IoUtils.closeQuietly(cachedResponseBody);
198c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath            }
199c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath            this.responseSource = ResponseSource.CACHE;
2007899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath            this.cacheResponse = GATEWAY_TIMEOUT_RESPONSE;
2017899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath            RawHeaders rawResponseHeaders
2027899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                    = RawHeaders.fromMultimap(cacheResponse.getHeaders(), true);
203c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath            setResponse(new ResponseHeaders(uri, rawResponseHeaders), cacheResponse.getBody());
204c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath        }
205c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath
206c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath        if (responseSource.requiresConnection()) {
207c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath            sendSocketRequest();
208c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath        } else if (connection != null) {
209c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath            HttpConnectionPool.INSTANCE.recycle(connection);
210c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath            connection = null;
211c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath        }
212c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath    }
213c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath
214c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath    /**
215c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath     * Initialize the source for this response. It may be corrected later if the
216c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath     * request headers forbids network use.
217c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath     */
218c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath    private void initResponseSource() throws IOException {
219c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath        responseSource = ResponseSource.NETWORK;
220c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath        if (!policy.getUseCaches() || responseCache == null) {
221c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath            return;
222c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath        }
223c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath
224c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath        CacheResponse candidate = responseCache.get(uri, method,
2257899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                requestHeaders.getHeaders().toMultimap(false));
226c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath        if (candidate == null) {
227c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath            return;
228c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath        }
229c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath
230c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath        Map<String, List<String>> responseHeadersMap = candidate.getHeaders();
231c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath        cachedResponseBody = candidate.getBody();
232c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath        if (!acceptCacheResponseType(candidate)
233c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath                || responseHeadersMap == null
234c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath                || cachedResponseBody == null) {
235c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath            IoUtils.closeQuietly(cachedResponseBody);
236c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath            return;
237c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath        }
238c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath
2397899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        RawHeaders rawResponseHeaders = RawHeaders.fromMultimap(responseHeadersMap, true);
240c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath        cachedResponseHeaders = new ResponseHeaders(uri, rawResponseHeaders);
241c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath        long now = System.currentTimeMillis();
242c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath        this.responseSource = cachedResponseHeaders.chooseResponseSource(now, requestHeaders);
243c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath        if (responseSource == ResponseSource.CACHE) {
244c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath            this.cacheResponse = candidate;
245c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath            setResponse(cachedResponseHeaders, cachedResponseBody);
246c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath        } else if (responseSource == ResponseSource.CONDITIONAL_CACHE) {
247c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath            this.cacheResponse = candidate;
248c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath        } else if (responseSource == ResponseSource.NETWORK) {
249c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath            IoUtils.closeQuietly(cachedResponseBody);
250c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath        } else {
251c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath            throw new AssertionError();
252c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath        }
253c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath    }
254c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath
255c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath    private void sendSocketRequest() throws IOException {
256c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath        if (connection == null) {
257c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath            connect();
258c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath        }
259c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath
260c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath        if (transport != null) {
261c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath            throw new IllegalStateException();
262c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath        }
263c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath
264c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath        transport = connection.newTransport(this);
265c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath
266c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath        if (hasRequestBody() && requestBodyOut == null) {
267c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath            // Create a request body if we don't have one already. We'll already
268c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath            // have one if we're retrying a failed POST.
269c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath            requestBodyOut = transport.createRequestBody();
270c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath        }
271c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath    }
272c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath
273c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath    /**
274c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath     * Connect to the origin server either directly or via a proxy.
275c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath     */
276c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath    protected void connect() throws IOException {
2777899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        if (connection != null) {
2787899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath            return;
279c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath        }
2807899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        connection = HttpConnection.connect(uri, getSslSocketFactory(), getHostnameVerifier(),
2817899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                policy.getProxy(), policy.getConnectTimeout(), policy.getReadTimeout(),
2827899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                getTunnelConfig());
2837899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        Proxy proxy = connection.getAddress().getProxy();
284c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath        if (proxy != null) {
285c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath            policy.setProxy(proxy);
286c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath            // Add the authority to the request line when we're using a proxy.
2877899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath            requestHeaders.getHeaders().setRequestLine(getRequestLine());
288c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath        }
289c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath    }
290c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath
291c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath    /**
292c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath     * @param body the response body, or null if it doesn't exist or isn't
293c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath     *     available.
294c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath     */
295c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath    private void setResponse(ResponseHeaders headers, InputStream body) throws IOException {
296c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath        if (this.responseBodyIn != null) {
297c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath            throw new IllegalStateException();
298c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath        }
299c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath        this.responseHeaders = headers;
300c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath        if (body != null) {
301c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath            initContentStream(body);
302c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath        }
303c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath    }
304c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath
305c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath    boolean hasRequestBody() {
306c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath        return method == POST || method == PUT;
307c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath    }
308c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath
309c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath    /**
310c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath     * Returns the request body or null if this request doesn't have a body.
311c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath     */
312c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath    public final OutputStream getRequestBody() {
313c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath        if (responseSource == null) {
314c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath            throw new IllegalStateException();
315c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath        }
316c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath        return requestBodyOut;
317c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath    }
318c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath
319c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath    public final boolean hasResponse() {
320c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath        return responseHeaders != null;
321c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath    }
322c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath
323c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath    public final RequestHeaders getRequestHeaders() {
324c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath        return requestHeaders;
325c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath    }
326c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath
327c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath    public final ResponseHeaders getResponseHeaders() {
328c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath        if (responseHeaders == null) {
329c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath            throw new IllegalStateException();
330c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath        }
331c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath        return responseHeaders;
332c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath    }
333c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath
334c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath    public final int getResponseCode() {
335c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath        if (responseHeaders == null) {
336c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath            throw new IllegalStateException();
337c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath        }
338c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath        return responseHeaders.getHeaders().getResponseCode();
339c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath    }
340c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath
341c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath    public final InputStream getResponseBody() {
342c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath        if (responseHeaders == null) {
343c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath            throw new IllegalStateException();
344c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath        }
345c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath        return responseBodyIn;
346c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath    }
347c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath
348c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath    public final CacheResponse getCacheResponse() {
349c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath        return cacheResponse;
350c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath    }
351c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath
352c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath    public final HttpConnection getConnection() {
353c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath        return connection;
354c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath    }
355c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath
356c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath    public final boolean hasRecycledConnection() {
357c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath        return connection != null && connection.isRecycled();
358c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath    }
359c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath
360c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath    /**
361c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath     * Returns true if {@code cacheResponse} is of the right type. This
362c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath     * condition is necessary but not sufficient for the cached response to
363c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath     * be used.
364c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath     */
365c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath    protected boolean acceptCacheResponseType(CacheResponse cacheResponse) {
366c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath        return true;
367c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath    }
368c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath
369c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath    private void maybeCache() throws IOException {
370c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath        // Are we caching at all?
371c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath        if (!policy.getUseCaches() || responseCache == null) {
372c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath            return;
373c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath        }
374c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath
375c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath        // Should we cache this response for this request?
376c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath        if (!responseHeaders.isCacheable(requestHeaders)) {
377c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath            return;
378c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath        }
379c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath
380c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath        // Offer this request to the cache.
381c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath        cacheRequest = responseCache.put(uri, getHttpConnectionToCache());
382c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath    }
383c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath
384c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath    protected OkHttpConnection getHttpConnectionToCache() {
385c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath        return policy;
386c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath    }
387c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath
388c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath    /**
389c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath     * Cause the socket connection to be released to the connection pool when
390c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath     * it is no longer needed. If it is already unneeded, it will be pooled
391c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath     * immediately. Otherwise the connection is held so that redirects can be
392c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath     * handled by the same connection.
393c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath     */
394c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath    public final void automaticallyReleaseConnectionToPool() {
395c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath        automaticallyReleaseConnectionToPool = true;
396c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath        if (connection != null && connectionReleased) {
397c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath            HttpConnectionPool.INSTANCE.recycle(connection);
398c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath            connection = null;
399c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath        }
400c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath    }
401c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath
402c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath    /**
403c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath     * Releases this engine so that its resources may be either reused or
404c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath     * closed. Also call {@link #automaticallyReleaseConnectionToPool} unless
405c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath     * the connection will be used to follow a redirect.
406c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath     */
407c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath    public final void release(boolean reusable) {
408c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath        // If the response body comes from the cache, close it.
409c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath        if (responseBodyIn == cachedResponseBody) {
410c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath            IoUtils.closeQuietly(responseBodyIn);
411c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath        }
412c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath
413c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath        if (!connectionReleased && connection != null) {
414c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath            connectionReleased = true;
415c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath
4167899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath            if (!reusable || !transport.makeReusable(requestBodyOut, responseTransferIn)) {
417c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath                connection.closeSocketAndStreams();
418c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath                connection = null;
419c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath            } else if (automaticallyReleaseConnectionToPool) {
420c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath                HttpConnectionPool.INSTANCE.recycle(connection);
421c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath                connection = null;
422c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath            }
423c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath        }
424c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath    }
425c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath
426c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath    private void initContentStream(InputStream transferStream) throws IOException {
4277899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        responseTransferIn = transferStream;
428c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath        if (transparentGzip && responseHeaders.isContentEncodingGzip()) {
429c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath            /*
430c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath             * If the response was transparently gzipped, remove the gzip header field
431c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath             * so clients don't double decompress. http://b/3009828
432c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath             */
433c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath            responseHeaders.stripContentEncoding();
434c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath            responseBodyIn = new GZIPInputStream(transferStream);
435c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath        } else {
436c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath            responseBodyIn = transferStream;
437c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath        }
438c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath    }
439c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath
440c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath    /**
441c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath     * Returns true if the response must have a (possibly 0-length) body.
442c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath     * See RFC 2616 section 4.3.
443c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath     */
444c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath    public final boolean hasResponseBody() {
445c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath        int responseCode = responseHeaders.getHeaders().getResponseCode();
446c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath
447c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath        // HEAD requests never yield a body regardless of the response headers.
448c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath        if (method == HEAD) {
449c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath            return false;
450c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath        }
451c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath
4527899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        if ((responseCode < HTTP_CONTINUE || responseCode >= 200)
453c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath                && responseCode != HttpURLConnectionImpl.HTTP_NO_CONTENT
454c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath                && responseCode != HttpURLConnectionImpl.HTTP_NOT_MODIFIED) {
455c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath            return true;
456c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath        }
457c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath
458c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath        /*
459c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath         * If the Content-Length or Transfer-Encoding headers disagree with the
460c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath         * response code, the response is malformed. For best compatibility, we
461c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath         * honor the headers.
462c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath         */
463c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath        if (responseHeaders.getContentLength() != -1 || responseHeaders.isChunked()) {
464c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath            return true;
465c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath        }
466c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath
467c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath        return false;
468c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath    }
469c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath
470c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath    /**
471c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath     * Populates requestHeaders with defaults and cookies.
472c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath     *
473c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath     * <p>This client doesn't specify a default {@code Accept} header because it
474c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath     * doesn't know what content types the application is interested in.
475c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath     */
476c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath    private void prepareRawRequestHeaders() throws IOException {
4777899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        requestHeaders.getHeaders().setRequestLine(getRequestLine());
478c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath
479c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath        if (requestHeaders.getUserAgent() == null) {
480c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath            requestHeaders.setUserAgent(getDefaultUserAgent());
481c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath        }
482c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath
483c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath        if (requestHeaders.getHost() == null) {
484c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath            requestHeaders.setHost(getOriginAddress(policy.getURL()));
485c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath        }
486c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath
487c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath        // TODO: this shouldn't be set for SPDY (it's ignored)
488c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath        if ((connection == null || connection.httpMinorVersion != 0)
489c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath                && requestHeaders.getConnection() == null) {
490c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath            requestHeaders.setConnection("Keep-Alive");
491c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath        }
492c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath
493c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath        if (requestHeaders.getAcceptEncoding() == null) {
494c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath            transparentGzip = true;
495c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath            // TODO: this shouldn't be set for SPDY (it isn't necessary)
496c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath            requestHeaders.setAcceptEncoding("gzip");
497c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath        }
498c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath
499c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath        if (hasRequestBody() && requestHeaders.getContentType() == null) {
500c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath            requestHeaders.setContentType("application/x-www-form-urlencoded");
501c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath        }
502c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath
503c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath        long ifModifiedSince = policy.getIfModifiedSince();
504c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath        if (ifModifiedSince != 0) {
505c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath            requestHeaders.setIfModifiedSince(new Date(ifModifiedSince));
506c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath        }
507c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath
508c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath        CookieHandler cookieHandler = CookieHandler.getDefault();
509c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath        if (cookieHandler != null) {
510c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath            requestHeaders.addCookies(
5117899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                    cookieHandler.get(uri, requestHeaders.getHeaders().toMultimap(false)));
512c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath        }
513c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath    }
514c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath
515c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath    /**
516c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath     * Returns the request status line, like "GET / HTTP/1.1". This is exposed
517c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath     * to the application by {@link HttpURLConnectionImpl#getHeaderFields}, so
518c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath     * it needs to be set even if the transport is SPDY.
519c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath     */
520c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath    String getRequestLine() {
521c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath        String protocol = (connection == null || connection.httpMinorVersion != 0)
522c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath                ? "HTTP/1.1"
523c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath                : "HTTP/1.0";
524c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath        return method + " " + requestString() + " " + protocol;
525c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath    }
526c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath
527c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath    private String requestString() {
528c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath        URL url = policy.getURL();
529c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath        if (includeAuthorityInRequestLine()) {
530c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath            return url.toString();
531c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath        } else {
5327899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath            return requestPath(url);
5337899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        }
5347899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    }
5357899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
5367899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    /**
5377899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath     * Returns the path to request, like the '/' in 'GET / HTTP/1.1'. Never
5387899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath     * empty, even if the request URL is. Includes the query component if it
5397899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath     * exists.
5407899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath     */
5417899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    public static String requestPath(URL url) {
5427899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        String fileOnly = url.getFile();
5437899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        if (fileOnly == null) {
5447899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath            return "/";
5457899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        } else if (!fileOnly.startsWith("/")) {
5467899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath            return "/" + fileOnly;
5477899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        } else {
548c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath            return fileOnly;
549c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath        }
550c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath    }
551c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath
552c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath    /**
553c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath     * Returns true if the request line should contain the full URL with host
554c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath     * and port (like "GET http://android.com/foo HTTP/1.1") or only the path
555c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath     * (like "GET /foo HTTP/1.1").
556c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath     *
557c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath     * <p>This is non-final because for HTTPS it's never necessary to supply the
558c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath     * full URL, even if a proxy is in use.
559c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath     */
560c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath    protected boolean includeAuthorityInRequestLine() {
561c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath        return policy.usingProxy();
562c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath    }
563c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath
564c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath    /**
565c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath     * Returns the SSL configuration for connections created by this engine.
566c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath     * We cannot reuse HTTPS connections if the socket factory has changed.
567c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath     */
568c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath    protected SSLSocketFactory getSslSocketFactory() {
569c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath        return null;
570c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath    }
571c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath
5727899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    /**
5737899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath     * Returns the hostname verifier for connections created by this engine. We
5747899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath     * cannot reuse HTTPS connections if the hostname verifier has changed.
5757899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath     */
5767899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    protected HostnameVerifier getHostnameVerifier() {
5777899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        return null;
5787899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    }
5797899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
5807899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    public static final String getDefaultUserAgent() {
581c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath        String agent = System.getProperty("http.agent");
582c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath        return agent != null ? agent : ("Java" + System.getProperty("java.version"));
583c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath    }
584c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath
5857899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    public static String getOriginAddress(URL url) {
586c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath        int port = url.getPort();
587c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath        String result = url.getHost();
5887899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        if (port > 0 && port != Libcore.getDefaultPort(url.getProtocol())) {
589c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath            result = result + ":" + port;
590c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath        }
591c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath        return result;
592c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath    }
593c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath
594c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath    /**
595c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath     * Flushes the remaining request header and body, parses the HTTP response
596c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath     * headers and starts reading the HTTP response body if it exists.
597c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath     */
598c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath    public final void readResponse() throws IOException {
599c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath        if (hasResponse()) {
600c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath            return;
601c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath        }
602c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath
603c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath        if (responseSource == null) {
604c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath            throw new IllegalStateException("readResponse() without sendRequest()");
605c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath        }
606c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath
607c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath        if (!responseSource.requiresConnection()) {
608c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath            return;
609c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath        }
610c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath
611c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath        if (sentRequestMillis == -1) {
612c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath            if (requestBodyOut instanceof RetryableOutputStream) {
613c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath                int contentLength = ((RetryableOutputStream) requestBodyOut).contentLength();
614c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath                requestHeaders.setContentLength(contentLength);
615c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath            }
616c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath            transport.writeRequestHeaders();
617c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath        }
618c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath
619c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath        if (requestBodyOut != null) {
620c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath            requestBodyOut.close();
621c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath            if (requestBodyOut instanceof RetryableOutputStream) {
622c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath                transport.writeRequestBody((RetryableOutputStream) requestBodyOut);
623c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath            }
624c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath        }
625c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath
626c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath        transport.flushRequest();
627c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath
628c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath        responseHeaders = transport.readResponseHeaders();
629c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath        responseHeaders.setLocalTimestamps(sentRequestMillis, System.currentTimeMillis());
630c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath
631c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath        if (responseSource == ResponseSource.CONDITIONAL_CACHE) {
632c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath            if (cachedResponseHeaders.validate(responseHeaders)) {
633c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath                release(true);
634c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath                ResponseHeaders combinedHeaders = cachedResponseHeaders.combine(responseHeaders);
635c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath                setResponse(combinedHeaders, cachedResponseBody);
636c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath                if (responseCache instanceof ExtendedResponseCache) {
637c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath                    ExtendedResponseCache httpResponseCache = (ExtendedResponseCache) responseCache;
638c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath                    httpResponseCache.trackConditionalCacheHit();
639c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath                    httpResponseCache.update(cacheResponse, getHttpConnectionToCache());
640c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath                }
641c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath                return;
642c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath            } else {
643c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath                IoUtils.closeQuietly(cachedResponseBody);
644c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath            }
645c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath        }
646c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath
647c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath        if (hasResponseBody()) {
648c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath            maybeCache(); // reentrant. this calls into user code which may call back into this!
649c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath        }
650c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath
651c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath        initContentStream(transport.getTransferStream(cacheRequest));
652c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath    }
6537899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
6547899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    protected HttpConnection.TunnelConfig getTunnelConfig() {
6557899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        return null;
6567899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    }
657c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath}
658