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 2025/02/12 15:09:44 UTC

(httpcomponents-core) branch master updated (be9902826 -> b0b040b27)

This is an automated email from the ASF dual-hosted git repository.

olegk pushed a change to branch master
in repository https://gitbox.apache.org/repos/asf/httpcomponents-core.git


    from be9902826 Protocol negotiation handlers to use exception callback to report unexpected exceptions during the protocol negotiation handshake
     new 9795bd843 Http1TestClient and Http1TestServer to provide configuration for custom message readers / writers
     new b0b040b27 Bug fix: Corrected state tracking of pipelined message exchanges by   HTTP/1.1 async client protocol handler

The 2 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 .../hc/core5/testing/nio/Http1TestClient.java      | 24 ++++++++++++
 .../hc/core5/testing/nio/Http1TestServer.java      | 24 ++++++++++++
 .../InternalClientHttp1EventHandlerFactory.java    |  6 ++-
 .../InternalServerHttp1EventHandlerFactory.java    |  6 ++-
 .../hc/core5/testing/nio/Http1IntegrationTest.java | 44 ++++++++++++++++++++++
 .../http/impl/nio/ClientHttp1StreamDuplexer.java   |  4 +-
 6 files changed, 102 insertions(+), 6 deletions(-)


(httpcomponents-core) 01/02: Http1TestClient and Http1TestServer to provide configuration for custom message readers / writers

Posted by ol...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

olegk pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/httpcomponents-core.git

commit 9795bd843dba5ef7e76243a7268027d8bec7bc5d
Author: Oleg Kalnichevski <ol...@apache.org>
AuthorDate: Wed Feb 12 15:07:08 2025 +0100

    Http1TestClient and Http1TestServer to provide configuration for custom message readers / writers
---
 .../hc/core5/testing/nio/Http1TestClient.java      | 24 ++++++++++++++++++++++
 .../hc/core5/testing/nio/Http1TestServer.java      | 24 ++++++++++++++++++++++
 .../InternalClientHttp1EventHandlerFactory.java    |  6 ++++--
 .../InternalServerHttp1EventHandlerFactory.java    |  6 ++++--
 .../hc/core5/testing/nio/Http1IntegrationTest.java |  2 ++
 5 files changed, 58 insertions(+), 4 deletions(-)

diff --git a/httpcore5-testing/src/main/java/org/apache/hc/core5/testing/nio/Http1TestClient.java b/httpcore5-testing/src/main/java/org/apache/hc/core5/testing/nio/Http1TestClient.java
index abb896cc9..aaf2e60ae 100644
--- a/httpcore5-testing/src/main/java/org/apache/hc/core5/testing/nio/Http1TestClient.java
+++ b/httpcore5-testing/src/main/java/org/apache/hc/core5/testing/nio/Http1TestClient.java
@@ -36,10 +36,14 @@
 import org.apache.hc.core5.concurrent.CompletingFutureContribution;
 import org.apache.hc.core5.concurrent.FutureCallback;
 import org.apache.hc.core5.http.HttpHost;
+import org.apache.hc.core5.http.HttpRequest;
+import org.apache.hc.core5.http.HttpResponse;
 import org.apache.hc.core5.http.config.CharCodingConfig;
 import org.apache.hc.core5.http.config.Http1Config;
 import org.apache.hc.core5.http.impl.DefaultConnectionReuseStrategy;
 import org.apache.hc.core5.http.impl.HttpProcessors;
+import org.apache.hc.core5.http.nio.NHttpMessageParserFactory;
+import org.apache.hc.core5.http.nio.NHttpMessageWriterFactory;
 import org.apache.hc.core5.http.protocol.HttpProcessor;
 import org.apache.hc.core5.reactor.IOReactorConfig;
 import org.apache.hc.core5.reactor.IOReactorStatus;
@@ -56,6 +60,8 @@ public class Http1TestClient extends AsyncRequester {
 
     private Http1Config http1Config;
     private HttpProcessor httpProcessor;
+    private NHttpMessageParserFactory<HttpResponse> responseParserFactory;
+    private NHttpMessageWriterFactory<HttpRequest> requestWriterFactory;
 
     public Http1TestClient(
             final IOReactorConfig ioReactorConfig,
@@ -92,6 +98,22 @@ public void configure(final HttpProcessor httpProcessor) {
         this.httpProcessor = httpProcessor;
     }
 
+    /**
+     * @since 5.4
+     */
+    public void configure(final NHttpMessageParserFactory<HttpResponse> responseParserFactory) {
+        ensureNotRunning();
+        this.responseParserFactory = responseParserFactory;
+    }
+
+    /**
+     * @since 5.4
+     */
+    public void configure(final NHttpMessageWriterFactory<HttpRequest> requestWriterFactory) {
+        ensureNotRunning();
+        this.requestWriterFactory = requestWriterFactory;
+    }
+
     /**
      * @deprecated Use {@link #configure(Http1Config)}, {@link #configure(HttpProcessor)}, {@link #start()}.
      */
@@ -118,6 +140,8 @@ public void start() throws IOException {
                 http1Config,
                 CharCodingConfig.DEFAULT,
                 DefaultConnectionReuseStrategy.INSTANCE,
+                responseParserFactory,
+                requestWriterFactory,
                 sslContext,
                 sslSessionInitializer,
                 sslSessionVerifier));
diff --git a/httpcore5-testing/src/main/java/org/apache/hc/core5/testing/nio/Http1TestServer.java b/httpcore5-testing/src/main/java/org/apache/hc/core5/testing/nio/Http1TestServer.java
index 341be6251..604fce147 100644
--- a/httpcore5-testing/src/main/java/org/apache/hc/core5/testing/nio/Http1TestServer.java
+++ b/httpcore5-testing/src/main/java/org/apache/hc/core5/testing/nio/Http1TestServer.java
@@ -37,6 +37,8 @@
 
 import org.apache.hc.core5.function.Decorator;
 import org.apache.hc.core5.function.Supplier;
+import org.apache.hc.core5.http.HttpRequest;
+import org.apache.hc.core5.http.HttpResponse;
 import org.apache.hc.core5.http.config.CharCodingConfig;
 import org.apache.hc.core5.http.config.Http1Config;
 import org.apache.hc.core5.http.impl.DefaultConnectionReuseStrategy;
@@ -44,6 +46,8 @@
 import org.apache.hc.core5.http.impl.routing.RequestRouter;
 import org.apache.hc.core5.http.nio.AsyncServerExchangeHandler;
 import org.apache.hc.core5.http.nio.AsyncServerRequestHandler;
+import org.apache.hc.core5.http.nio.NHttpMessageParserFactory;
+import org.apache.hc.core5.http.nio.NHttpMessageWriterFactory;
 import org.apache.hc.core5.http.nio.support.BasicAsyncServerExpectationDecorator;
 import org.apache.hc.core5.http.nio.support.BasicServerExchangeHandler;
 import org.apache.hc.core5.http.nio.support.DefaultAsyncResponseExchangeHandlerFactory;
@@ -66,6 +70,8 @@ public class Http1TestServer extends AsyncServer {
 
     private Http1Config http1Config;
     private HttpProcessor httpProcessor;
+    private NHttpMessageParserFactory<HttpRequest> requestParserFactory;
+    private NHttpMessageWriterFactory<HttpResponse> responseWriterFactory;
     private Decorator<AsyncServerExchangeHandler> exchangeHandlerDecorator;
 
     public Http1TestServer(
@@ -123,6 +129,22 @@ public void configure(final Decorator<AsyncServerExchangeHandler> exchangeHandle
         this.exchangeHandlerDecorator = exchangeHandlerDecorator;
     }
 
+    /**
+     * @since 5.4
+     */
+    public void configure(final NHttpMessageParserFactory<HttpRequest> requestParserFactory) {
+        ensureNotRunning();
+        this.requestParserFactory = requestParserFactory;
+    }
+
+    /**
+     * @since 5.4
+     */
+    public void configure(final NHttpMessageWriterFactory<HttpResponse> responseWriterFactory) {
+        ensureNotRunning();
+        this.responseWriterFactory = responseWriterFactory;
+    }
+
     public InetSocketAddress start(final IOEventHandlerFactory handlerFactory) throws Exception {
         execute(handlerFactory);
         final Future<ListenerEndpoint> future = listen(new InetSocketAddress(0));
@@ -163,6 +185,8 @@ public InetSocketAddress start() throws Exception {
                 http1Config,
                 CharCodingConfig.DEFAULT,
                 DefaultConnectionReuseStrategy.INSTANCE,
+                requestParserFactory,
+                responseWriterFactory,
                 sslContext,
                 sslSessionInitializer,
                 sslSessionVerifier));
diff --git a/httpcore5-testing/src/main/java/org/apache/hc/core5/testing/nio/InternalClientHttp1EventHandlerFactory.java b/httpcore5-testing/src/main/java/org/apache/hc/core5/testing/nio/InternalClientHttp1EventHandlerFactory.java
index e28ab6bf8..360c12126 100644
--- a/httpcore5-testing/src/main/java/org/apache/hc/core5/testing/nio/InternalClientHttp1EventHandlerFactory.java
+++ b/httpcore5-testing/src/main/java/org/apache/hc/core5/testing/nio/InternalClientHttp1EventHandlerFactory.java
@@ -77,6 +77,8 @@ class InternalClientHttp1EventHandlerFactory implements IOEventHandlerFactory {
             final Http1Config http1Config,
             final CharCodingConfig charCodingConfig,
             final ConnectionReuseStrategy connectionReuseStrategy,
+            final NHttpMessageParserFactory<HttpResponse> responseParserFactory,
+            final NHttpMessageWriterFactory<HttpRequest> requestWriterFactory,
             final SSLContext sslContext,
             final SSLSessionInitializer sslSessionInitializer,
             final SSLSessionVerifier sslSessionVerifier) {
@@ -86,8 +88,8 @@ class InternalClientHttp1EventHandlerFactory implements IOEventHandlerFactory {
         this.connectionReuseStrategy = connectionReuseStrategy != null ? connectionReuseStrategy :
                 DefaultConnectionReuseStrategy.INSTANCE;
         this.sslContext = sslContext;
-        this.responseParserFactory = new DefaultHttpResponseParserFactory(this.http1Config);
-        this.requestWriterFactory = DefaultHttpRequestWriterFactory.INSTANCE;
+        this.responseParserFactory = responseParserFactory != null ? responseParserFactory : new DefaultHttpResponseParserFactory(this.http1Config);
+        this.requestWriterFactory = requestWriterFactory != null ? requestWriterFactory : DefaultHttpRequestWriterFactory.INSTANCE;
         this.sslSessionInitializer = sslSessionInitializer;
         this.sslSessionVerifier = sslSessionVerifier;
     }
diff --git a/httpcore5-testing/src/main/java/org/apache/hc/core5/testing/nio/InternalServerHttp1EventHandlerFactory.java b/httpcore5-testing/src/main/java/org/apache/hc/core5/testing/nio/InternalServerHttp1EventHandlerFactory.java
index a7225d71f..2c81f580d 100644
--- a/httpcore5-testing/src/main/java/org/apache/hc/core5/testing/nio/InternalServerHttp1EventHandlerFactory.java
+++ b/httpcore5-testing/src/main/java/org/apache/hc/core5/testing/nio/InternalServerHttp1EventHandlerFactory.java
@@ -83,6 +83,8 @@ class InternalServerHttp1EventHandlerFactory implements IOEventHandlerFactory {
             final Http1Config http1Config,
             final CharCodingConfig charCodingConfig,
             final ConnectionReuseStrategy connectionReuseStrategy,
+            final NHttpMessageParserFactory<HttpRequest> requestParserFactory,
+            final NHttpMessageWriterFactory<HttpResponse> responseWriterFactory,
             final SSLContext sslContext,
             final SSLSessionInitializer sslSessionInitializer,
             final SSLSessionVerifier sslSessionVerifier) {
@@ -95,8 +97,8 @@ class InternalServerHttp1EventHandlerFactory implements IOEventHandlerFactory {
         this.sslContext = sslContext;
         this.sslSessionInitializer = sslSessionInitializer;
         this.sslSessionVerifier = sslSessionVerifier;
-        this.requestParserFactory = new DefaultHttpRequestParserFactory(this.http1Config);
-        this.responseWriterFactory = new DefaultHttpResponseWriterFactory(this.http1Config);
+        this.requestParserFactory = requestParserFactory != null ? requestParserFactory : new DefaultHttpRequestParserFactory(this.http1Config);
+        this.responseWriterFactory = responseWriterFactory != null ? responseWriterFactory : new DefaultHttpResponseWriterFactory(this.http1Config);
     }
 
     protected ServerHttp1StreamDuplexer createServerHttp1StreamDuplexer(
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 da33ae5ea..c2899fd4a 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
@@ -1711,6 +1711,8 @@ protected void handle(
                 Http1Config.DEFAULT,
                 CharCodingConfig.DEFAULT,
                 DefaultConnectionReuseStrategy.INSTANCE,
+                null,
+                null,
                 scheme == URIScheme.HTTPS ? SSLTestContexts.createServerSSLContext() : null, null, null) {
 
             @Override


(httpcomponents-core) 02/02: Bug fix: Corrected state tracking of pipelined message exchanges by HTTP/1.1 async client protocol handler

Posted by ol...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

olegk pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/httpcomponents-core.git

commit b0b040b27cca2449460903227d37104a0e2411b8
Author: Oleg Kalnichevski <ol...@apache.org>
AuthorDate: Wed Feb 12 15:14:30 2025 +0100

    Bug fix: Corrected state tracking of pipelined message exchanges by   HTTP/1.1 async client protocol handler
---
 .../hc/core5/testing/nio/Http1IntegrationTest.java | 42 ++++++++++++++++++++++
 .../http/impl/nio/ClientHttp1StreamDuplexer.java   |  4 +--
 2 files changed, 44 insertions(+), 2 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 c2899fd4a..6c7472a82 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
@@ -57,6 +57,7 @@
 import java.util.concurrent.locks.ReentrantLock;
 
 import org.apache.hc.core5.function.Callback;
+import org.apache.hc.core5.http.ConnectionClosedException;
 import org.apache.hc.core5.http.ConnectionReuseStrategy;
 import org.apache.hc.core5.http.ContentLengthStrategy;
 import org.apache.hc.core5.http.ContentType;
@@ -82,6 +83,8 @@
 import org.apache.hc.core5.http.impl.Http1StreamListener;
 import org.apache.hc.core5.http.impl.HttpProcessors;
 import org.apache.hc.core5.http.impl.nio.AbstractContentEncoder;
+import org.apache.hc.core5.http.impl.nio.DefaultHttpRequestFactory;
+import org.apache.hc.core5.http.impl.nio.DefaultHttpRequestParser;
 import org.apache.hc.core5.http.impl.nio.ServerHttp1StreamDuplexer;
 import org.apache.hc.core5.http.message.BasicHttpRequest;
 import org.apache.hc.core5.http.message.BasicHttpResponse;
@@ -2112,4 +2115,43 @@ void testHeaderTooLargePost() throws Exception {
         Assertions.assertEquals("Maximum line length limit exceeded", result1.getBody());
     }
 
+    @Test
+    void testInvalidRequestMessage() throws Exception {
+        final Http1Config http1Config = Http1Config.DEFAULT;
+        final Http1TestServer server = resources.server();
+        server.configure(http1Config);
+        server.configure(() -> new DefaultHttpRequestParser<HttpRequest>(http1Config, DefaultHttpRequestFactory.INSTANCE) {
+
+            @Override
+            protected HttpRequest createMessage(final CharArrayBuffer buffer) throws HttpException {
+                throw new RuntimeException("Ka-boom");
+            }
+
+        });
+
+        server.register("/hello", () -> new SingleLineResponseHandler("Hi there"));
+
+        final InetSocketAddress serverEndpoint = server.start();
+        final HttpHost target = target(serverEndpoint);
+
+        final Http1TestClient client = resources.client();
+
+        client.start();
+        final Future<ClientSessionEndpoint> connectFuture = client.connect(
+                "localhost", serverEndpoint.getPort(), TIMEOUT);
+        final ClientSessionEndpoint streamEndpoint = connectFuture.get();
+
+        final BasicHttpRequest request = BasicRequestBuilder.get()
+                .setHttpHost(target)
+                .setPath("/hello")
+                .build();
+
+        final Future<Message<HttpResponse, String>> future = streamEndpoint.execute(
+                new BasicRequestProducer(request, null),
+                new BasicResponseConsumer<>(new StringAsyncEntityConsumer()), null);
+        final ExecutionException executionException = Assertions.assertThrows(ExecutionException.class, () ->
+                future.get(TIMEOUT.getDuration(), TIMEOUT.getTimeUnit()));
+        Assertions.assertInstanceOf(ConnectionClosedException.class, executionException.getCause());
+    }
+
 }
diff --git a/httpcore5/src/main/java/org/apache/hc/core5/http/impl/nio/ClientHttp1StreamDuplexer.java b/httpcore5/src/main/java/org/apache/hc/core5/http/impl/nio/ClientHttp1StreamDuplexer.java
index 7299d7251..a67b9926e 100644
--- a/httpcore5/src/main/java/org/apache/hc/core5/http/impl/nio/ClientHttp1StreamDuplexer.java
+++ b/httpcore5/src/main/java/org/apache/hc/core5/http/impl/nio/ClientHttp1StreamDuplexer.java
@@ -288,12 +288,12 @@ protected ContentEncoder createContentEncoder(
 
     @Override
     boolean inputIdle() {
-        return incoming == null;
+        return incoming == null && pipeline.isEmpty();
     }
 
     @Override
     boolean outputIdle() {
-        return outgoing == null && pipeline.isEmpty();
+        return outgoing == null;
     }
 
     @Override