Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 58 additions & 0 deletions okhttp-tests/src/test/java/okhttp3/CallTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -1583,6 +1583,22 @@ private void postBodyRetransmittedAfterAuthorizationFail(String body) throws Exc
assertEquals("Body", response.body().string());
}

@Test public void getClientRequestTimeoutWithBackPressure() throws Exception {
server.enqueue(new MockResponse()
.setSocketPolicy(SocketPolicy.DISCONNECT_AT_END)
.setResponseCode(408)
.setHeader("Connection", "Close")
.setHeader("Retry-After", "1")
.setBody("You took too long!"));

Request request = new Request.Builder()
.url(server.url("/"))
.build();
Response response = client.newCall(request).execute();

assertEquals("You took too long!", response.body().string());
}

@Test public void requestBodyRetransmittedOnClientRequestTimeout() throws Exception {
server.enqueue(new MockResponse()
.setSocketPolicy(SocketPolicy.DISCONNECT_AT_END)
Expand Down Expand Up @@ -1649,6 +1665,48 @@ private void postBodyRetransmittedAfterAuthorizationFail(String body) throws Exc
assertEquals(2, server.getRequestCount());
}

@Test public void maxUnavailableTimeoutRetries() throws IOException {
server.enqueue(new MockResponse()
.setSocketPolicy(SocketPolicy.DISCONNECT_AT_END)
.setResponseCode(503)
.setHeader("Connection", "Close")
.setHeader("Retry-After", "0")
.setBody("You took too long!"));
server.enqueue(new MockResponse()
.setSocketPolicy(SocketPolicy.DISCONNECT_AT_END)
.setResponseCode(503)
.setHeader("Connection", "Close")
.setHeader("Retry-After", "0")
.setBody("You took too long!"));

Request request = new Request.Builder()
.url(server.url("/"))
.build();
Response response = client.newCall(request).execute();

assertEquals(503, response.code());
assertEquals("You took too long!", response.body().string());

assertEquals(2, server.getRequestCount());
}

@Test public void retryOnUnavailableWith0RetryAfter() throws IOException {
server.enqueue(new MockResponse()
.setSocketPolicy(SocketPolicy.DISCONNECT_AT_END)
.setResponseCode(503)
.setHeader("Connection", "Close")
.setHeader("Retry-After", "0")
.setBody("You took too long!"));
server.enqueue(new MockResponse().setBody("Body"));

Request request = new Request.Builder()
.url(server.url("/"))
.build();
Response response = client.newCall(request).execute();

assertEquals("Body", response.body().string());
}

@Test public void propfindRedirectsToPropfindAndMaintainsRequestBody() throws Exception {
// given
server.enqueue(new MockResponse()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
import static java.net.HttpURLConnection.HTTP_PROXY_AUTH;
import static java.net.HttpURLConnection.HTTP_SEE_OTHER;
import static java.net.HttpURLConnection.HTTP_UNAUTHORIZED;
import static java.net.HttpURLConnection.HTTP_UNAVAILABLE;
import static okhttp3.internal.Util.closeQuietly;
import static okhttp3.internal.http.StatusLine.HTTP_PERM_REDIRECT;
import static okhttp3.internal.http.StatusLine.HTTP_TEMP_REDIRECT;
Expand Down Expand Up @@ -359,13 +360,47 @@ private Request followUpRequest(Response userResponse) throws IOException {
return null;
}

if (retryAfter(userResponse, 0) > 0) {
return null;
}

return userResponse.request();

case HTTP_UNAVAILABLE:
if (userResponse.priorResponse() != null
&& userResponse.priorResponse().code() == HTTP_UNAVAILABLE) {
// We attempted to retry and got another timeout. Give up.
return null;
}

if (retryAfter(userResponse, Integer.MAX_VALUE) == 0) {
// specifically received an instruction to retry without delay
return userResponse.request();
}

return null;

default:
return null;
}
}

private int retryAfter(Response userResponse, int defaultDelay) {
String header = userResponse.header("Retry-After");

if (header == null) {
return defaultDelay;
}

// https://tools.ietf.org/html/rfc7231#section-7.1.3
// currently ignores a HTTP-date, and assumes any non int 0 is a delay
if (header.matches("\\d+")) {
return Integer.valueOf(header);
}

return Integer.MAX_VALUE;
}

/**
* Returns true if an HTTP request for {@code followUp} can reuse the connection used by this
* engine.
Expand Down