1a82f42bbeedd0b07f3892f3b0efaa8122dc8f264Narayan Kamath/* 2a82f42bbeedd0b07f3892f3b0efaa8122dc8f264Narayan Kamath * Copyright (C) 2013 Square, Inc. 3a82f42bbeedd0b07f3892f3b0efaa8122dc8f264Narayan Kamath * 4a82f42bbeedd0b07f3892f3b0efaa8122dc8f264Narayan Kamath * Licensed under the Apache License, Version 2.0 (the "License"); 5a82f42bbeedd0b07f3892f3b0efaa8122dc8f264Narayan Kamath * you may not use this file except in compliance with the License. 6a82f42bbeedd0b07f3892f3b0efaa8122dc8f264Narayan Kamath * You may obtain a copy of the License at 7a82f42bbeedd0b07f3892f3b0efaa8122dc8f264Narayan Kamath * 8a82f42bbeedd0b07f3892f3b0efaa8122dc8f264Narayan Kamath * http://www.apache.org/licenses/LICENSE-2.0 9a82f42bbeedd0b07f3892f3b0efaa8122dc8f264Narayan Kamath * 10a82f42bbeedd0b07f3892f3b0efaa8122dc8f264Narayan Kamath * Unless required by applicable law or agreed to in writing, software 11a82f42bbeedd0b07f3892f3b0efaa8122dc8f264Narayan Kamath * distributed under the License is distributed on an "AS IS" BASIS, 12a82f42bbeedd0b07f3892f3b0efaa8122dc8f264Narayan Kamath * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13a82f42bbeedd0b07f3892f3b0efaa8122dc8f264Narayan Kamath * See the License for the specific language governing permissions and 14a82f42bbeedd0b07f3892f3b0efaa8122dc8f264Narayan Kamath * limitations under the License. 15a82f42bbeedd0b07f3892f3b0efaa8122dc8f264Narayan Kamath */ 16166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamathpackage com.squareup.okhttp; 17a82f42bbeedd0b07f3892f3b0efaa8122dc8f264Narayan Kamath 183c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fullerimport com.squareup.okhttp.internal.NamedRunnable; 193c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fullerimport com.squareup.okhttp.internal.http.HttpAuthenticator; 203c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fullerimport com.squareup.okhttp.internal.http.HttpEngine; 213c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fullerimport com.squareup.okhttp.internal.http.HttpURLConnectionImpl; 223c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fullerimport com.squareup.okhttp.internal.http.OkHeaders; 23a82f42bbeedd0b07f3892f3b0efaa8122dc8f264Narayan Kamathimport java.io.IOException; 243c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fullerimport java.io.InputStream; 253c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fullerimport java.net.ProtocolException; 263c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fullerimport java.net.Proxy; 273c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fullerimport java.net.URL; 283c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fullerimport okio.BufferedSink; 293c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fullerimport okio.Okio; 303c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fullerimport okio.Source; 31a82f42bbeedd0b07f3892f3b0efaa8122dc8f264Narayan Kamath 323c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fullerimport static com.squareup.okhttp.internal.Util.getEffectivePort; 333c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fullerimport static com.squareup.okhttp.internal.http.HttpURLConnectionImpl.HTTP_MOVED_PERM; 343c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fullerimport static com.squareup.okhttp.internal.http.HttpURLConnectionImpl.HTTP_MOVED_TEMP; 353c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fullerimport static com.squareup.okhttp.internal.http.HttpURLConnectionImpl.HTTP_MULT_CHOICE; 363c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fullerimport static com.squareup.okhttp.internal.http.HttpURLConnectionImpl.HTTP_PROXY_AUTH; 373c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fullerimport static com.squareup.okhttp.internal.http.HttpURLConnectionImpl.HTTP_SEE_OTHER; 383c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fullerimport static com.squareup.okhttp.internal.http.HttpURLConnectionImpl.HTTP_UNAUTHORIZED; 393c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fullerimport static com.squareup.okhttp.internal.http.StatusLine.HTTP_TEMP_REDIRECT; 40a82f42bbeedd0b07f3892f3b0efaa8122dc8f264Narayan Kamath 413c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fullerfinal class Job extends NamedRunnable { 423c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller private final Dispatcher dispatcher; 433c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller private final OkHttpClient client; 443c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller private final Response.Receiver responseReceiver; 453c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller private int redirectionCount; 463c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 473c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller volatile boolean canceled; 483c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 493c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller /** The request; possibly a consequence of redirects or auth headers. */ 503c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller private Request request; 513c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller HttpEngine engine; 523c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 533c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller public Job(Dispatcher dispatcher, OkHttpClient client, Request request, 54a82f42bbeedd0b07f3892f3b0efaa8122dc8f264Narayan Kamath Response.Receiver responseReceiver) { 553c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller super("OkHttp %s", request.urlString()); 56a82f42bbeedd0b07f3892f3b0efaa8122dc8f264Narayan Kamath this.dispatcher = dispatcher; 573c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller this.client = client; 58a82f42bbeedd0b07f3892f3b0efaa8122dc8f264Narayan Kamath this.request = request; 59a82f42bbeedd0b07f3892f3b0efaa8122dc8f264Narayan Kamath this.responseReceiver = responseReceiver; 60a82f42bbeedd0b07f3892f3b0efaa8122dc8f264Narayan Kamath } 61a82f42bbeedd0b07f3892f3b0efaa8122dc8f264Narayan Kamath 623c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller String host() { 633c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller return request.url().getHost(); 643c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 653c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 663c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller Request request() { 673c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller return request; 683c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 693c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 703c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller Object tag() { 713c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller return request.tag(); 723c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 733c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 743c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller @Override protected void execute() { 75a82f42bbeedd0b07f3892f3b0efaa8122dc8f264Narayan Kamath try { 763c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller Response response = getResponse(); 773c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller if (response != null && !canceled) { 783c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller responseReceiver.onResponse(response); 793c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 80a82f42bbeedd0b07f3892f3b0efaa8122dc8f264Narayan Kamath } catch (IOException e) { 81a82f42bbeedd0b07f3892f3b0efaa8122dc8f264Narayan Kamath responseReceiver.onFailure(new Failure.Builder() 82a82f42bbeedd0b07f3892f3b0efaa8122dc8f264Narayan Kamath .request(request) 83a82f42bbeedd0b07f3892f3b0efaa8122dc8f264Narayan Kamath .exception(e) 84a82f42bbeedd0b07f3892f3b0efaa8122dc8f264Narayan Kamath .build()); 85a82f42bbeedd0b07f3892f3b0efaa8122dc8f264Narayan Kamath } finally { 863c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller engine.close(); // Close the connection if it isn't already. 87a82f42bbeedd0b07f3892f3b0efaa8122dc8f264Narayan Kamath dispatcher.finished(this); 88a82f42bbeedd0b07f3892f3b0efaa8122dc8f264Narayan Kamath } 89a82f42bbeedd0b07f3892f3b0efaa8122dc8f264Narayan Kamath } 90a82f42bbeedd0b07f3892f3b0efaa8122dc8f264Narayan Kamath 913c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller /** 923c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller * Performs the request and returns the response. May return null if this job 933c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller * was canceled. 943c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller */ 953c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller Response getResponse() throws IOException { 963c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller Response redirectedBy = null; 973c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 983c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller // Copy body metadata to the appropriate request headers. 99a82f42bbeedd0b07f3892f3b0efaa8122dc8f264Narayan Kamath Request.Body body = request.body(); 100a82f42bbeedd0b07f3892f3b0efaa8122dc8f264Narayan Kamath if (body != null) { 1013c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller MediaType contentType = body.contentType(); 1023c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller if (contentType == null) throw new IllegalStateException("contentType == null"); 1033c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 1043c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller Request.Builder requestBuilder = request.newBuilder(); 1053c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller requestBuilder.header("Content-Type", contentType.toString()); 1063c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 107a82f42bbeedd0b07f3892f3b0efaa8122dc8f264Narayan Kamath long contentLength = body.contentLength(); 1083c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller if (contentLength != -1) { 1093c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller requestBuilder.header("Content-Length", Long.toString(contentLength)); 1103c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller requestBuilder.removeHeader("Transfer-Encoding"); 111a82f42bbeedd0b07f3892f3b0efaa8122dc8f264Narayan Kamath } else { 1123c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller requestBuilder.header("Transfer-Encoding", "chunked"); 1133c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller requestBuilder.removeHeader("Content-Length"); 1143c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 1153c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 1163c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller request = requestBuilder.build(); 1173c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 1183c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 1193c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller // Create the initial HTTP engine. Retries and redirects need new engine for each attempt. 1202ee29995b7bd1068991884a54ca14e9aeeff1a58Neil Fuller engine = new HttpEngine(client, request, false, null, null, null, null); 1213c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 1223c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller while (true) { 1233c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller if (canceled) return null; 1243c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 1253c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller try { 1263c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller engine.sendRequest(); 1273c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 1283c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller if (body != null) { 1293c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller BufferedSink sink = Okio.buffer(engine.getRequestBody()); 1303c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller body.writeTo(sink); 1313c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller sink.flush(); 1323c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 1333c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 1343c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller engine.readResponse(); 1353c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } catch (IOException e) { 1363c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller HttpEngine retryEngine = engine.recover(e); 1373c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller if (retryEngine != null) { 1383c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller engine = retryEngine; 1393c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller continue; 1403c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 1413c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 1423c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller // Give up; recovery is not possible. 1433c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller throw e; 1443c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 1453c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 1463c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller Response response = engine.getResponse(); 1473c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller Request redirect = processResponse(engine, response); 1483c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 1493c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller if (redirect == null) { 1503c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller engine.releaseConnection(); 1513c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller return response.newBuilder() 152c6bd683320121544811f481709b3fdbcbe9b3866Neil Fuller .body(new RealResponseBody(response, engine.getResponseBody())) 1532ee29995b7bd1068991884a54ca14e9aeeff1a58Neil Fuller .priorResponse(redirectedBy) 1543c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller .build(); 155a82f42bbeedd0b07f3892f3b0efaa8122dc8f264Narayan Kamath } 1563c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 1573c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller if (!sameConnection(request, redirect)) { 1583c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller engine.releaseConnection(); 1593c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 1603c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 1613c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller Connection connection = engine.close(); 1622ee29995b7bd1068991884a54ca14e9aeeff1a58Neil Fuller redirectedBy = response.newBuilder().priorResponse(redirectedBy).build(); // Chained. 1633c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller request = redirect; 1642ee29995b7bd1068991884a54ca14e9aeeff1a58Neil Fuller engine = new HttpEngine(client, request, false, connection, null, null, null); 1653c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 1663c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 1673c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 1683c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller /** 1693c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller * Figures out the HTTP request to make in response to receiving {@code 1703c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller * response}. This will either add authentication headers or follow 1713c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller * redirects. If a follow-up is either unnecessary or not applicable, this 1723c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller * returns null. 1733c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller */ 1743c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller private Request processResponse(HttpEngine engine, Response response) throws IOException { 1753c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller Request request = response.request(); 1763c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller Proxy selectedProxy = engine.getRoute() != null 1773c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller ? engine.getRoute().getProxy() 1783c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller : client.getProxy(); 1793c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller int responseCode = response.code(); 1803c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 1813c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller switch (responseCode) { 1823c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller case HTTP_PROXY_AUTH: 1833c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller if (selectedProxy.type() != Proxy.Type.HTTP) { 1843c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller throw new ProtocolException("Received HTTP_PROXY_AUTH (407) code while not using proxy"); 1853c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 1863c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller // fall-through 1873c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller case HTTP_UNAUTHORIZED: 1883c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller return HttpAuthenticator.processAuthHeader( 1893c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller client.getAuthenticator(), response, selectedProxy); 1903c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 1913c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller case HTTP_MULT_CHOICE: 1923c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller case HTTP_MOVED_PERM: 1933c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller case HTTP_MOVED_TEMP: 1943c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller case HTTP_SEE_OTHER: 1953c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller case HTTP_TEMP_REDIRECT: 1963c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller if (!client.getFollowProtocolRedirects()) { 1973c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller return null; // This client has is configured to not follow redirects. 1983c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 1993c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 2003c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller if (++redirectionCount > HttpURLConnectionImpl.MAX_REDIRECTS) { 2013c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller throw new ProtocolException("Too many redirects: " + redirectionCount); 2023c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 2033c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 2043c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller String method = request.method(); 2053c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller if (responseCode == HTTP_TEMP_REDIRECT && !method.equals("GET") && !method.equals("HEAD")) { 2063c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller // "If the 307 status code is received in response to a request other than GET or HEAD, 2073c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller // the user agent MUST NOT automatically redirect the request" 2083c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller return null; 2093c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 2103c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 2113c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller String location = response.header("Location"); 2123c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller if (location == null) { 2133c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller return null; 2143c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 2153c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 2163c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller URL url = new URL(request.url(), location); 2173c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller if (!url.getProtocol().equals("https") && !url.getProtocol().equals("http")) { 2183c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller return null; // Don't follow redirects to unsupported protocols. 2193c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 2203c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 2213c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller return this.request.newBuilder().url(url).build(); 2223c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 2233c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller default: 2243c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller return null; 225a82f42bbeedd0b07f3892f3b0efaa8122dc8f264Narayan Kamath } 226a82f42bbeedd0b07f3892f3b0efaa8122dc8f264Narayan Kamath } 227a82f42bbeedd0b07f3892f3b0efaa8122dc8f264Narayan Kamath 2283c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller static boolean sameConnection(Request a, Request b) { 2293c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller return a.url().getHost().equals(b.url().getHost()) 2303c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller && getEffectivePort(a.url()) == getEffectivePort(b.url()) 2313c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller && a.url().getProtocol().equals(b.url().getProtocol()); 2323c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 2333c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 2343c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller static class RealResponseBody extends Response.Body { 2353c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller private final Response response; 2363c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller private final Source source; 2373c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 2383c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller /** Multiple calls to {@link #byteStream} must return the same instance. */ 2393c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller private InputStream in; 240a82f42bbeedd0b07f3892f3b0efaa8122dc8f264Narayan Kamath 2413c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller RealResponseBody(Response response, Source source) { 2423c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller this.response = response; 2433c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller this.source = source; 244a82f42bbeedd0b07f3892f3b0efaa8122dc8f264Narayan Kamath } 245a82f42bbeedd0b07f3892f3b0efaa8122dc8f264Narayan Kamath 2463c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller @Override public boolean ready() throws IOException { 2473c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller return true; 2483c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 2493c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 2503c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller @Override public MediaType contentType() { 2513c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller String contentType = response.header("Content-Type"); 2523c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller return contentType != null ? MediaType.parse(contentType) : null; 2533c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 2543c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 2553c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller @Override public long contentLength() { 2563c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller return OkHeaders.contentLength(response); 2573c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 2583c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 2593c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller @Override public Source source() { 2603c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller return source; 2613c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 2623c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 2633c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller @Override public InputStream byteStream() { 2643c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller InputStream result = in; 2653c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller return result != null 2663c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller ? result 2673c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller : (in = Okio.buffer(source).inputStream()); 2683c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 269a82f42bbeedd0b07f3892f3b0efaa8122dc8f264Narayan Kamath } 270a82f42bbeedd0b07f3892f3b0efaa8122dc8f264Narayan Kamath} 271