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
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -444,7 +444,7 @@
<dependency>
<groupId>org.apache.httpcomponents.client5</groupId>
<artifactId>httpclient5</artifactId>
<version>5.3.1</version>
<version>5.6.3</version>
</dependency>
<dependency>
<groupId>com.nimbusds</groupId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ final class ApacheHttp2Request extends LowLevelHttpRequest {
private SimpleHttpRequest request;
private final RequestConfig.Builder requestConfig;
private int writeTimeout;
private int readTimeout;
private ApacheHttp2AsyncEntityProducer entityProducer;
private ApacheHttp2AsyncEntityConsumer entityConsumer;

Expand All @@ -57,6 +58,7 @@ final class ApacheHttp2Request extends LowLevelHttpRequest {
this.httpAsyncClient = httpAsyncClient;
this.requestBuilder = requestBuilder;
this.writeTimeout = 0;
this.readTimeout = 0;

this.requestConfig = RequestConfig.custom()
.setRedirectsEnabled(false);
Expand All @@ -69,6 +71,7 @@ public void addHeader(String name, String value) {

@Override
public void setTimeout(int connectionTimeout, int readTimeout) throws IOException {
this.readTimeout = readTimeout;
requestConfig
.setConnectTimeout(Timeout.ofMilliseconds(connectionTimeout))
.setResponseTimeout(Timeout.ofMilliseconds(readTimeout));
Expand Down Expand Up @@ -125,7 +128,10 @@ public void cancelled() {

// Wait for response
try {
final Message<HttpResponse, ApacheHttp2Entity> response = responseFuture.get();
final Message<HttpResponse, ApacheHttp2Entity> response =
readTimeout > 0
? responseFuture.get(readTimeout, TimeUnit.MILLISECONDS)
: responseFuture.get();
return new ApacheHttp2Response(response);
} catch (ExecutionException e) {
if (e.getCause() instanceof ConnectTimeoutException
Expand All @@ -142,6 +148,9 @@ public void cancelled() {
throw new IOException("Request Interrupted", e);
} catch (CancellationException e) {
throw new IOException("Request Cancelled", e);
} catch (TimeoutException e) {
responseFuture.cancel(true);
throw new IOException("Stream exception in request", e);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we specify that it was a read timeout here?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah good call! I thought about it but I wonder if that would break the backward compatibility in some way... even if it did, it would most likely be a minor risk I think

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's leave it like this for now because our priority is to get the dependency bumped. We can address that in a future PR.

}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,17 +58,16 @@
import org.apache.hc.core5.http.HttpStatus;
import org.apache.hc.core5.http.Message;
import org.apache.hc.core5.http.impl.bootstrap.HttpServer;
import org.apache.hc.core5.http.impl.io.HttpService;
import org.apache.hc.core5.http.impl.bootstrap.ServerBootstrap;
import org.apache.hc.core5.http.io.HttpRequestHandler;
import org.apache.hc.core5.http.io.entity.ByteArrayEntity;
import org.apache.hc.core5.http.io.support.BasicHttpServerRequestHandler;
import org.apache.hc.core5.http.message.BasicHttpResponse;
import org.apache.hc.core5.http.nio.AsyncPushConsumer;
import org.apache.hc.core5.http.nio.AsyncRequestProducer;
import org.apache.hc.core5.http.nio.AsyncResponseConsumer;
import org.apache.hc.core5.http.nio.HandlerFactory;
import org.apache.hc.core5.http.protocol.HttpContext;
import org.apache.hc.core5.http.protocol.HttpProcessor;
import org.apache.hc.core5.http.protocol.HttpProcessorBuilder;
import org.junit.Assert;
import org.junit.Test;

Expand Down Expand Up @@ -423,6 +422,39 @@ public void handle(
}
}

@Test
public void testReadTimeout() throws Exception {
final HttpRequestHandler handler = new HttpRequestHandler() {
@Override
public void handle(
ClassicHttpRequest request, ClassicHttpResponse response, HttpContext context)
throws HttpException, IOException {
try {
Thread.sleep(1000L);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
response.setCode(HttpStatus.SC_OK);
}
};

try (FakeServer server = new FakeServer(handler)) {
HttpTransport transport = new ApacheHttp2Transport();
GenericUrl testUrl = new GenericUrl("http://localhost/timeout");
testUrl.setPort(server.getPort());
com.google.api.client.http.HttpRequest request = transport.createRequestFactory()
.buildGetRequest(testUrl);
request.setReadTimeout(100);

try {
request.execute();
Assert.fail("Expected IOException on read timeout");
} catch (IOException e) {
assertEquals("Stream exception in request", e.getMessage());
}
}
}

private static class FakeServer implements AutoCloseable {
private final HttpServer server;

Expand All @@ -434,31 +466,11 @@ public HttpRequestHandler resolve(HttpRequest request, HttpContext context)
return httpHandler;
}
};
server = new HttpServer(
0,
HttpService.builder()
.withHttpProcessor(
new HttpProcessor() {
@Override
public void process(
HttpRequest request, EntityDetails entity, HttpContext context)
throws HttpException, IOException {
}

@Override
public void process(
HttpResponse response, EntityDetails entity, HttpContext context)
throws HttpException, IOException {
}
})
.withHttpServerRequestHandler(new BasicHttpServerRequestHandler(mapper))
.build(),
null,
null,
null,
null,
null,
null);
server = ServerBootstrap.bootstrap()
.setListenerPort(0)
.setHttpProcessor(HttpProcessorBuilder.create().build())
.setRequestRouter(mapper)
.create();
server.start();
}

Expand Down
Loading