You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@hc.apache.org by ol...@apache.org on 2019/09/30 13:09:11 UTC
[httpcomponents-core] 02/02: HTTPCORE-604: async HTTP/1.1 protocol
handler must close the i/o session if it cannot be kept alive before
passing control to the message exchange hanlder
This is an automated email from the ASF dual-hosted git repository.
olegk pushed a commit to branch bug-fixes
in repository https://gitbox.apache.org/repos/asf/httpcomponents-core.git
commit e326a64971573cd9a42dc77d65174a906bad85c0
Author: Oleg Kalnichevski <ol...@apache.org>
AuthorDate: Mon Sep 30 14:48:52 2019 +0200
HTTPCORE-604: async HTTP/1.1 protocol handler must close the i/o session if it cannot be kept alive before passing control to the message exchange hanlder
---
.../hc/core5/testing/nio/Http1IntegrationTest.java | 68 ++++++++++++++++++++++
.../testing/nio/Http1ServerAndRequesterTest.java | 29 +++++++++
.../http/impl/nio/ClientHttp1StreamHandler.java | 7 ++-
3 files changed, 101 insertions(+), 3 deletions(-)
diff --git a/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/nio/Http1IntegrationTest.java b/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/nio/Http1IntegrationTest.java
index e167c38..e82b566 100644
--- a/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/nio/Http1IntegrationTest.java
+++ b/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/nio/Http1IntegrationTest.java
@@ -108,6 +108,7 @@ import org.apache.hc.core5.http.nio.entity.DigestingEntityProducer;
import org.apache.hc.core5.http.nio.entity.StringAsyncEntityConsumer;
import org.apache.hc.core5.http.nio.entity.StringAsyncEntityProducer;
import org.apache.hc.core5.http.nio.support.AbstractServerExchangeHandler;
+import org.apache.hc.core5.http.nio.support.AsyncRequestBuilder;
import org.apache.hc.core5.http.nio.support.BasicAsyncServerExpectationDecorator;
import org.apache.hc.core5.http.nio.support.BasicRequestConsumer;
import org.apache.hc.core5.http.nio.support.BasicRequestProducer;
@@ -221,6 +222,40 @@ public class Http1IntegrationTest extends InternalHttp1ServerTestBase {
}
@Test
+ public void testSimpleGetConnectionClose() throws Exception {
+ server.register("/hello", new Supplier<AsyncServerExchangeHandler>() {
+
+ @Override
+ public AsyncServerExchangeHandler get() {
+ return new SingleLineResponseHandler("Hi there");
+ }
+
+ });
+ final InetSocketAddress serverEndpoint = server.start();
+
+ client.start();
+ final URI requestURI = createRequestURI(serverEndpoint, "/hello");
+ for (int i = 0; i < 5; i++) {
+ final Future<ClientSessionEndpoint> connectFuture = client.connect(
+ "localhost", serverEndpoint.getPort(), TIMEOUT);
+ try (final ClientSessionEndpoint streamEndpoint = connectFuture.get()) {
+ final Future<Message<HttpResponse, String>> future = streamEndpoint.execute(
+ AsyncRequestBuilder.get(requestURI)
+ .addHeader(HttpHeaders.CONNECTION, "close")
+ .build(),
+ new BasicResponseConsumer<>(new StringAsyncEntityConsumer()), null);
+ final Message<HttpResponse, String> result = future.get(TIMEOUT.getDuration(), TIMEOUT.getTimeUnit());
+ Assert.assertNotNull(result);
+ final HttpResponse response1 = result.getHead();
+ final String entity1 = result.getBody();
+ Assert.assertNotNull(response1);
+ Assert.assertEquals(200, response1.getCode());
+ Assert.assertEquals("Hi there", entity1);
+ }
+ }
+ }
+
+ @Test
public void testSimpleGetIdentityTransfer() throws Exception {
server.register("/hello", new Supplier<AsyncServerExchangeHandler>() {
@@ -654,6 +689,39 @@ public class Http1IntegrationTest extends InternalHttp1ServerTestBase {
}
@Test
+ public void testSimpleHeadConnectionClose() throws Exception {
+ server.register("/hello", new Supplier<AsyncServerExchangeHandler>() {
+
+ @Override
+ public AsyncServerExchangeHandler get() {
+ return new SingleLineResponseHandler("Hi there");
+ }
+
+ });
+ final InetSocketAddress serverEndpoint = server.start();
+
+ client.start();
+ final URI requestURI = createRequestURI(serverEndpoint, "/hello");
+ for (int i = 0; i < 5; i++) {
+ final Future<ClientSessionEndpoint> connectFuture = client.connect(
+ "localhost", serverEndpoint.getPort(), TIMEOUT);
+ try (final ClientSessionEndpoint streamEndpoint = connectFuture.get()) {
+ final Future<Message<HttpResponse, String>> future = streamEndpoint.execute(
+ AsyncRequestBuilder.head(requestURI)
+ .addHeader(HttpHeaders.CONNECTION, "close")
+ .build(),
+ new BasicResponseConsumer<>(new StringAsyncEntityConsumer()), null);
+ final Message<HttpResponse, String> result = future.get(TIMEOUT.getDuration(), TIMEOUT.getTimeUnit());
+ Assert.assertNotNull(result);
+ final HttpResponse response1 = result.getHead();
+ Assert.assertNotNull(response1);
+ Assert.assertEquals(200, response1.getCode());
+ Assert.assertNull(result.getBody());
+ }
+ }
+ }
+
+ @Test
public void testHeadPipelined() throws Exception {
server.register("/hello", new Supplier<AsyncServerExchangeHandler>() {
diff --git a/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/nio/Http1ServerAndRequesterTest.java b/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/nio/Http1ServerAndRequesterTest.java
index 04d8f5e..ee2679d 100644
--- a/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/nio/Http1ServerAndRequesterTest.java
+++ b/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/nio/Http1ServerAndRequesterTest.java
@@ -53,6 +53,7 @@ import org.apache.hc.core5.http.impl.bootstrap.AsyncServerBootstrap;
import org.apache.hc.core5.http.impl.bootstrap.HttpAsyncRequester;
import org.apache.hc.core5.http.impl.bootstrap.HttpAsyncServer;
import org.apache.hc.core5.http.impl.bootstrap.StandardFilters;
+import org.apache.hc.core5.http.message.BasicHttpRequest;
import org.apache.hc.core5.http.nio.AsyncClientEndpoint;
import org.apache.hc.core5.http.nio.AsyncDataConsumer;
import org.apache.hc.core5.http.nio.AsyncEntityProducer;
@@ -394,4 +395,32 @@ public class Http1ServerAndRequesterTest {
}
}
+ @Test
+ public void testNonPersistentHeads() throws Exception {
+ server.start();
+ final Future<ListenerEndpoint> future = server.listen(new InetSocketAddress(0));
+ final ListenerEndpoint listener = future.get();
+ final InetSocketAddress address = (InetSocketAddress) listener.getAddress();
+ requester.start();
+
+ final HttpHost target = new HttpHost(scheme.id, "localhost", address.getPort());
+ final Queue<Future<Message<HttpResponse, String>>> queue = new LinkedList<>();
+
+ for (int i = 0; i < 20; i++) {
+ final HttpRequest head = new BasicHttpRequest(Methods.HEAD, target, "/no-keep-alive/stuff?p=" + i);
+ queue.add(requester.execute(
+ new BasicRequestProducer(head, null),
+ new BasicResponseConsumer<>(new StringAsyncEntityConsumer()), TIMEOUT, null));
+ }
+
+ while (!queue.isEmpty()) {
+ final Future<Message<HttpResponse, String>> resultFuture = queue.remove();
+ final Message<HttpResponse, String> message = resultFuture.get(TIMEOUT.getDuration(), TIMEOUT.getTimeUnit());
+ Assert.assertThat(message, CoreMatchers.notNullValue());
+ final HttpResponse response = message.getHead();
+ Assert.assertThat(response.getCode(), CoreMatchers.equalTo(HttpStatus.SC_OK));
+ Assert.assertThat(message.getBody(), CoreMatchers.nullValue());
+ }
+ }
+
}
diff --git a/httpcore5/src/main/java/org/apache/hc/core5/http/impl/nio/ClientHttp1StreamHandler.java b/httpcore5/src/main/java/org/apache/hc/core5/http/impl/nio/ClientHttp1StreamHandler.java
index 2edb807..aebd5aa 100644
--- a/httpcore5/src/main/java/org/apache/hc/core5/http/impl/nio/ClientHttp1StreamHandler.java
+++ b/httpcore5/src/main/java/org/apache/hc/core5/http/impl/nio/ClientHttp1StreamHandler.java
@@ -247,11 +247,12 @@ class ClientHttp1StreamHandler implements ResourceHolder {
context.setAttribute(HttpCoreContext.HTTP_RESPONSE, response);
httpProcessor.process(response, entityDetails, context);
+ if (entityDetails == null && !keepAlive) {
+ outputChannel.close();
+ }
+
exchangeHandler.consumeResponse(response, entityDetails, context);
if (entityDetails == null) {
- if (!keepAlive) {
- outputChannel.close();
- }
responseState = MessageState.COMPLETE;
} else {
responseState = MessageState.BODY;