diff --git a/src/main/java/com/squareup/okhttp/internal/http/HttpURLConnectionImpl.java b/src/main/java/com/squareup/okhttp/internal/http/HttpURLConnectionImpl.java index ff0a2c421..25e8c3c86 100644 --- a/src/main/java/com/squareup/okhttp/internal/http/HttpURLConnectionImpl.java +++ b/src/main/java/com/squareup/okhttp/internal/http/HttpURLConnectionImpl.java @@ -60,6 +60,10 @@ import static com.squareup.okhttp.internal.Util.getEffectivePort; * is currently connected to a server. */ public class HttpURLConnectionImpl extends HttpURLConnection { + + /** Numeric status code, 307: Temporary Redirect. */ + static final int HTTP_TEMP_REDIRECT = 307; + /** * How many redirects should we follow? Chrome follows 21; Firefox, curl, * and wget follow 20; Safari follows 16; and HTTP/1.0 recommends 5. @@ -400,7 +404,8 @@ public class HttpURLConnectionImpl extends HttpURLConnection { Proxy selectedProxy = httpEngine.connection != null ? httpEngine.connection.getProxy() : requestedProxy; - switch (getResponseCode()) { + final int responseCode = getResponseCode(); + switch (responseCode) { case HTTP_PROXY_AUTH: if (selectedProxy.type() != Proxy.Type.HTTP) { throw new ProtocolException("Received HTTP_PROXY_AUTH (407) code while not using proxy"); @@ -415,12 +420,18 @@ public class HttpURLConnectionImpl extends HttpURLConnection { case HTTP_MOVED_PERM: case HTTP_MOVED_TEMP: case HTTP_SEE_OTHER: + case HTTP_TEMP_REDIRECT: if (!getInstanceFollowRedirects()) { return Retry.NONE; } if (++redirectionCount > MAX_REDIRECTS) { throw new ProtocolException("Too many redirects: " + redirectionCount); } + if (responseCode == HTTP_TEMP_REDIRECT && !method.equals("GET") && !method.equals("HEAD")) { + // "If the 307 status code is received in response to a request other than GET or HEAD, + // the user agent MUST NOT automatically redirect the request" + return Retry.NONE; + } String location = getHeaderField("Location"); if (location == null) { return Retry.NONE; diff --git a/src/test/java/com/squareup/okhttp/internal/http/URLConnectionTest.java b/src/test/java/com/squareup/okhttp/internal/http/URLConnectionTest.java index 9a3572aaa..fc87b6f82 100644 --- a/src/test/java/com/squareup/okhttp/internal/http/URLConnectionTest.java +++ b/src/test/java/com/squareup/okhttp/internal/http/URLConnectionTest.java @@ -1731,6 +1731,70 @@ public final class URLConnectionTest { assertEquals(1, server.getRequestCount()); } + @Test public void response307WithGet() throws Exception { + test307Redirect("GET"); + } + + @Test public void response307WithHead() throws Exception { + test307Redirect("HEAD"); + } + + @Test public void response307WithOptions() throws Exception { + test307Redirect("OPTIONS"); + } + + @Test public void response307WithPost() throws Exception { + test307Redirect("POST"); + } + + private void test307Redirect(String method) throws Exception { + MockResponse response1 = new MockResponse() + .setResponseCode(HttpURLConnectionImpl.HTTP_TEMP_REDIRECT) + .addHeader("Location: /page2"); + if (!method.equals("HEAD")) { + response1.setBody("This page has moved!"); + } + server.enqueue(response1); + server.enqueue(new MockResponse().setBody("Page 2")); + server.play(); + + HttpURLConnection connection = client.open(server.getUrl("/page1")); + connection.setRequestMethod(method); + byte[] requestBody = { 'A', 'B', 'C', 'D' }; + if (method.equals("POST")) { + connection.setDoOutput(true); + OutputStream outputStream = connection.getOutputStream(); + outputStream.write(requestBody); + outputStream.close(); + } + + String response = readAscii(connection.getInputStream(), Integer.MAX_VALUE); + + RecordedRequest page1 = server.takeRequest(); + assertEquals(method + " /page1 HTTP/1.1", page1.getRequestLine()); + + if (method.equals("GET")) { + assertEquals("Page 2", response); + } else if (method.equals("HEAD")) { + assertTrue(response.isEmpty()); + } else { + // Methods other than GET/HEAD shouldn't follow the redirect + if (method.equals("POST")) { + assertTrue(connection.getDoOutput()); + assertEquals(Arrays.toString(requestBody), Arrays.toString(page1.getBody())); + } + assertEquals(1, server.getRequestCount()); + assertEquals("This page has moved!", response); + return; + } + + // GET/HEAD requests should have followed the redirect with the same method + assertFalse(connection.getDoOutput()); + assertEquals(2, server.getRequestCount()); + RecordedRequest page2 = server.takeRequest(); + assertEquals(method + " /page2 HTTP/1.1", page2.getRequestLine()); + } + @Test public void follow20Redirects() throws Exception { for (int i = 0; i < 20; i++) { server.enqueue(new MockResponse().setResponseCode(HttpURLConnection.HTTP_MOVED_TEMP)