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