New Upstream Release - httpcomponents-core5

Ready changes

Summary

Merged new upstream version: 5.2.2 (was: 5.2.1).

Resulting package

Built on 2023-06-21T17:09 (took 6m41s)

The resulting binary packages can be installed (if you have the apt repository enabled) by running one of:

apt install -t fresh-releases libhttpcore5-java

Lintian Result

Diff

diff --git a/RELEASE_NOTES.txt b/RELEASE_NOTES.txt
index 8560411..315aa20 100644
--- a/RELEASE_NOTES.txt
+++ b/RELEASE_NOTES.txt
@@ -1,3 +1,40 @@
+Release 5.2.2
+------------------
+
+This is a maintenance release that corrects several defects discovered since release 5.2.1 including
+a major defect that can cause HTTP/2 connections allocate excessive amount of memory for their output
+frame buffer if the opposite endpoint transmits a high value of MAX_FRAME_SIZE in its settings.
+
+
+Change Log
+-------------------
+
+* HTTPCORE-752: I/O reactor fails to initialize socket timeout for TLS connections correctly resulting
+  in infinite (no timeout) by default.
+  Contributed by Oleg Kalnichevski <olegk at apache.org>
+
+* HTTPCORE-751: H2 protocol handler always resizes the output frame buffer to the remove
+  MAX_FRAME_SIZE instead of doing so only then the remote MAX_FRAME_SIZE is lesser than
+  the current MAX_FRAME_SIZE (partially reverts HTTPCORE-707).
+  Contributed by Oleg Kalnichevski <olegk at apache.org>
+
+* HTTPCORE-750: Fixed a defect causing AbstractIOSessionPool to create multiple connections under
+  high load at initialization time due to a race condition.
+  Contributed by Oleg Kalnichevski <olegk at apache.org>
+
+* Handle UnsupportedOperationException in getApplicationProtocol.
+  Contributed by Arturo Bernal <arturobernalg at gmail.com>
+
+* HTTPCORE-742: BasicHttpRequest#setUri does not correctly reset internal state.
+  Contributed by Oleg Kalnichevski <olegk at apache.org>
+
+* HTTPCORE-733: BasicAsyncEntityProducer sends an extra trailing 0 with UTF-8 encoded content
+  Contributed by Oleg Kalnichevski <olegk at apache.org>
+
+* Do not duplicate the HttpMessage instance variable slot in subclasses of AbstractMessageWrapper.
+  Contributed by Gary Gregory <ggregory at apache.org>
+
+
 Release 5.2.1
 ------------------
 
diff --git a/debian/changelog b/debian/changelog
index f10eac7..5d84347 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,9 @@
+httpcomponents-core5 (5.2.2-1) UNRELEASED; urgency=low
+
+  * New upstream release.
+
+ -- Debian Janitor <janitor@jelmer.uk>  Wed, 21 Jun 2023 17:04:16 -0000
+
 httpcomponents-core5 (5.2.1-1) unstable; urgency=medium
 
   * New upstream version 5.2.1.
diff --git a/debian/patches/no-Conscrypt-support.patch b/debian/patches/no-Conscrypt-support.patch
index 68cd739..bfe1bab 100644
--- a/debian/patches/no-Conscrypt-support.patch
+++ b/debian/patches/no-Conscrypt-support.patch
@@ -7,11 +7,11 @@ Forwarded: not-needed
  .../org/apache/hc/core5/http2/ssl/ConscryptSupport.java     | 13 ++-----------
  1 file changed, 2 insertions(+), 11 deletions(-)
 
-diff --git a/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/ssl/ConscryptSupport.java b/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/ssl/ConscryptSupport.java
-index 6e4010e..abbb0f8 100644
---- a/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/ssl/ConscryptSupport.java
-+++ b/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/ssl/ConscryptSupport.java
-@@ -34,7 +34,6 @@ import org.apache.hc.core5.http.ssl.TlsCiphers;
+Index: httpcomponents-core5.git/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/ssl/ConscryptSupport.java
+===================================================================
+--- httpcomponents-core5.git.orig/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/ssl/ConscryptSupport.java
++++ httpcomponents-core5.git/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/ssl/ConscryptSupport.java
+@@ -34,7 +34,6 @@ import org.apache.hc.core5.http.ssl.TlsC
  import org.apache.hc.core5.reactor.ssl.SSLSessionInitializer;
  import org.apache.hc.core5.reactor.ssl.SSLSessionVerifier;
  import org.apache.hc.core5.reactor.ssl.TlsDetails;
diff --git a/httpcore5-h2/pom.xml b/httpcore5-h2/pom.xml
index 16f1f8e..54d178d 100644
--- a/httpcore5-h2/pom.xml
+++ b/httpcore5-h2/pom.xml
@@ -28,7 +28,7 @@
   <parent>
     <groupId>org.apache.httpcomponents.core5</groupId>
     <artifactId>httpcore5-parent</artifactId>
-    <version>5.2.1</version>
+    <version>5.2.2</version>
   </parent>
   <artifactId>httpcore5-h2</artifactId>
   <name>Apache HttpComponents Core HTTP/2</name>
diff --git a/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/nio/AbstractH2StreamMultiplexer.java b/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/nio/AbstractH2StreamMultiplexer.java
index a6020d8..6431c43 100644
--- a/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/nio/AbstractH2StreamMultiplexer.java
+++ b/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/nio/AbstractH2StreamMultiplexer.java
@@ -28,6 +28,7 @@ package org.apache.hc.core5.http2.impl.nio;
 
 import java.io.IOException;
 import java.net.SocketAddress;
+import java.nio.BufferOverflowException;
 import java.nio.ByteBuffer;
 import java.nio.channels.SelectionKey;
 import java.nio.charset.CharacterCodingException;
@@ -1219,8 +1220,12 @@ abstract class AbstractH2StreamMultiplexer implements Identifiable, HttpConnecti
         initOutputWinSize = remoteConfig.getInitialWindowSize();
 
         final int maxFrameSize = remoteConfig.getMaxFrameSize();
-        if (maxFrameSize > localConfig.getMaxFrameSize()) {
-            outputBuffer.expand(maxFrameSize);
+        if (maxFrameSize < outputBuffer.getMaxFramePayloadSize()) {
+            try {
+                outputBuffer.resize(maxFrameSize);
+            } catch (final BufferOverflowException ex) {
+                throw new H2ConnectionException(H2Error.INTERNAL_ERROR, "Failure resizing the frame output buffer");
+            }
         }
 
         if (delta != 0) {
diff --git a/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/nio/FrameOutputBuffer.java b/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/nio/FrameOutputBuffer.java
index f20edfb..479365a 100644
--- a/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/nio/FrameOutputBuffer.java
+++ b/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/nio/FrameOutputBuffer.java
@@ -45,8 +45,8 @@ import org.apache.hc.core5.util.Args;
 public final class FrameOutputBuffer {
 
     private final BasicH2TransportMetrics metrics;
-    private volatile int maxFramePayloadSize;
-    private volatile ByteBuffer buffer;
+    private int maxFramePayloadSize;
+    private ByteBuffer buffer;
 
     public FrameOutputBuffer(final BasicH2TransportMetrics metrics, final int maxFramePayloadSize) {
         Args.notNull(metrics, "HTTP2 transport metrics");
@@ -60,7 +60,28 @@ public final class FrameOutputBuffer {
         this(new BasicH2TransportMetrics(), maxFramePayloadSize);
     }
 
+    /**
+     * @deprecated Misnomer. Use {@link #resize(int)}.
+     */
+    @Deprecated
     public void expand(final int maxFramePayloadSize) {
+        resize(maxFramePayloadSize);
+    }
+
+    /**
+     * @since 5.2
+     */
+    public int getMaxFramePayloadSize() {
+        return maxFramePayloadSize;
+    }
+
+    /**
+     * @since 5.2
+     */
+    public void resize(final int maxFramePayloadSize) {
+        if (buffer.capacity() == maxFramePayloadSize) {
+            return;
+        }
         this.maxFramePayloadSize = maxFramePayloadSize;
         final ByteBuffer newBuffer = ByteBuffer.allocate(FrameConsts.HEAD_LEN + maxFramePayloadSize);
         if (buffer.position() > 0) {
diff --git a/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/nio/bootstrap/H2MultiplexingRequester.java b/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/nio/bootstrap/H2MultiplexingRequester.java
index 082ce9e..d4edea9 100644
--- a/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/nio/bootstrap/H2MultiplexingRequester.java
+++ b/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/nio/bootstrap/H2MultiplexingRequester.java
@@ -285,4 +285,9 @@ public class H2MultiplexingRequester extends AsyncRequester{
         return execute(requestProducer, responseConsumer, null, timeout, null, callback);
     }
 
+    @Internal
+    public H2ConnPool getConnPool() {
+        return connPool;
+    }
+
 }
diff --git a/httpcore5-h2/src/test/java/org/apache/hc/core5/http2/impl/nio/TestFrameInOutBuffers.java b/httpcore5-h2/src/test/java/org/apache/hc/core5/http2/impl/nio/TestFrameInOutBuffers.java
index dc1662f..e949535 100644
--- a/httpcore5-h2/src/test/java/org/apache/hc/core5/http2/impl/nio/TestFrameInOutBuffers.java
+++ b/httpcore5-h2/src/test/java/org/apache/hc/core5/http2/impl/nio/TestFrameInOutBuffers.java
@@ -289,5 +289,13 @@ public class TestFrameInOutBuffers {
                 inBuffer.read(readableChannel));
     }
 
+    @Test
+    public void testOutputBufferResize() throws Exception {
+        final FrameOutputBuffer outBuffer = new FrameOutputBuffer(16 * 1024);
+        Assertions.assertEquals(16 * 1024, outBuffer.getMaxFramePayloadSize());
+        outBuffer.resize(1024);
+        Assertions.assertEquals(1024, outBuffer.getMaxFramePayloadSize());
+    }
+
 }
 
diff --git a/httpcore5-reactive/pom.xml b/httpcore5-reactive/pom.xml
index d1c50c8..2e1d483 100644
--- a/httpcore5-reactive/pom.xml
+++ b/httpcore5-reactive/pom.xml
@@ -27,7 +27,7 @@
   <parent>
     <artifactId>httpcore5-parent</artifactId>
     <groupId>org.apache.httpcomponents.core5</groupId>
-    <version>5.2.1</version>
+    <version>5.2.2</version>
   </parent>
   <modelVersion>4.0.0</modelVersion>
 
diff --git a/httpcore5-testing/pom.xml b/httpcore5-testing/pom.xml
index bd23bbc..2bbd20e 100644
--- a/httpcore5-testing/pom.xml
+++ b/httpcore5-testing/pom.xml
@@ -28,7 +28,7 @@
   <parent>
     <groupId>org.apache.httpcomponents.core5</groupId>
     <artifactId>httpcore5-parent</artifactId>
-    <version>5.2.1</version>
+    <version>5.2.2</version>
   </parent>
   <artifactId>httpcore5-testing</artifactId>
   <name>Apache HttpComponents Core Integration Tests</name>
diff --git a/httpcore5-testing/src/main/java/org/apache/hc/core5/testing/nio/LoggingIOSessionListener.java b/httpcore5-testing/src/main/java/org/apache/hc/core5/testing/nio/LoggingIOSessionListener.java
index 509a9ae..7350884 100644
--- a/httpcore5-testing/src/main/java/org/apache/hc/core5/testing/nio/LoggingIOSessionListener.java
+++ b/httpcore5-testing/src/main/java/org/apache/hc/core5/testing/nio/LoggingIOSessionListener.java
@@ -27,6 +27,7 @@
 
 package org.apache.hc.core5.testing.nio;
 
+import org.apache.hc.core5.annotation.Internal;
 import org.apache.hc.core5.http.ConnectionClosedException;
 import org.apache.hc.core5.reactor.IOSession;
 import org.apache.hc.core5.reactor.IOSessionListener;
@@ -39,7 +40,8 @@ public class LoggingIOSessionListener implements IOSessionListener {
 
     private final Logger connLog = LoggerFactory.getLogger("org.apache.hc.core5.http.connection");
 
-    private LoggingIOSessionListener() {
+    @Internal
+    public LoggingIOSessionListener() {
     }
 
     @Override
diff --git a/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/nio/H2ConnPoolTest.java b/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/nio/H2ConnPoolTest.java
new file mode 100644
index 0000000..1d78315
--- /dev/null
+++ b/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/nio/H2ConnPoolTest.java
@@ -0,0 +1,180 @@
+/*
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation.  For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.hc.core5.testing.nio;
+
+import java.net.InetSocketAddress;
+import java.util.concurrent.ConcurrentLinkedQueue;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.Future;
+import java.util.concurrent.atomic.AtomicLong;
+
+import org.apache.hc.core5.concurrent.FutureCallback;
+import org.apache.hc.core5.http.HttpHost;
+import org.apache.hc.core5.http.URIScheme;
+import org.apache.hc.core5.http.impl.bootstrap.HttpAsyncServer;
+import org.apache.hc.core5.http2.HttpVersionPolicy;
+import org.apache.hc.core5.http2.impl.nio.bootstrap.H2MultiplexingRequester;
+import org.apache.hc.core5.http2.nio.command.PingCommand;
+import org.apache.hc.core5.http2.nio.pool.H2ConnPool;
+import org.apache.hc.core5.http2.nio.support.BasicPingHandler;
+import org.apache.hc.core5.reactor.Command;
+import org.apache.hc.core5.reactor.IOReactorConfig;
+import org.apache.hc.core5.reactor.IOSession;
+import org.apache.hc.core5.reactor.ListenerEndpoint;
+import org.apache.hc.core5.testing.nio.extension.H2AsyncServerResource;
+import org.apache.hc.core5.testing.nio.extension.H2MultiplexingRequesterResource;
+import org.apache.hc.core5.util.Timeout;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.RegisterExtension;
+
+public class H2ConnPoolTest {
+
+    private static final Timeout TIMEOUT = Timeout.ofSeconds(30);
+
+    private final AtomicLong clientConnCount;
+    @RegisterExtension
+    private final H2AsyncServerResource serverResource;
+    @RegisterExtension
+    private final H2MultiplexingRequesterResource clientResource;
+
+    public H2ConnPoolTest() throws Exception {
+        this.serverResource = new H2AsyncServerResource(bootstrap -> bootstrap
+                .setVersionPolicy(HttpVersionPolicy.FORCE_HTTP_2)
+                .setIOReactorConfig(
+                        IOReactorConfig.custom()
+                                .setSoTimeout(TIMEOUT)
+                                .build())
+                .register("*", () -> new EchoHandler(2048))
+        );
+
+        this.clientConnCount = new AtomicLong();
+        this.clientResource = new H2MultiplexingRequesterResource(bootstrap -> bootstrap
+                .setIOReactorConfig(IOReactorConfig.custom()
+                        .setSoTimeout(TIMEOUT)
+                        .build())
+                .setIOSessionListener(new LoggingIOSessionListener() {
+
+                    @Override
+                    public void connected(final IOSession session) {
+                        clientConnCount.incrementAndGet();
+                        super.connected(session);
+                    }
+
+                })
+        );
+    }
+
+    @BeforeEach
+    public void resetCounts() {
+        clientConnCount.set(0);
+    }
+
+    @Test
+    public void testManyGetSession() throws Exception {
+        final int n = 200;
+
+        final HttpAsyncServer server = serverResource.start();
+        final Future<ListenerEndpoint> future = server.listen(new InetSocketAddress(0), URIScheme.HTTP);
+        final ListenerEndpoint listener = future.get();
+        final InetSocketAddress address = (InetSocketAddress) listener.getAddress();
+        final HttpHost target = new HttpHost(URIScheme.HTTP.id, "localhost", address.getPort());
+
+        final H2MultiplexingRequester requester = clientResource.start();
+        final H2ConnPool connPool = requester.getConnPool();
+        final CountDownLatch latch = new CountDownLatch(n);
+        for (int i = 0; i < n; i++) {
+            connPool.getSession(target, TIMEOUT, new FutureCallback<IOSession>() {
+
+                @Override
+                public void completed(final IOSession session) {
+                    session.enqueue(new PingCommand(new BasicPingHandler(
+                            result -> {
+                                latch.countDown();
+                            })), Command.Priority.IMMEDIATE);
+                }
+
+                @Override
+                public void failed(final Exception ex) {
+                    latch.countDown();
+                }
+
+                @Override
+                public void cancelled() {
+                    latch.countDown();
+                }
+
+            });
+        }
+        Assertions.assertTrue(latch.await(TIMEOUT.getDuration(), TIMEOUT.getTimeUnit()));
+
+        requester.initiateShutdown();
+        requester.awaitShutdown(TIMEOUT);
+
+        Assertions.assertEquals(1, clientConnCount.get());
+    }
+
+    @Test
+    public void testManyGetSessionFailures() throws Exception {
+        final int n = 200;
+
+        final HttpHost target = new HttpHost(URIScheme.HTTP.id, "pampa.invalid", 8888);
+
+        final H2MultiplexingRequester requester = clientResource.start();
+        final H2ConnPool connPool = requester.getConnPool();
+        final CountDownLatch latch = new CountDownLatch(n);
+        final ConcurrentLinkedQueue<Long> concurrentConnections = new ConcurrentLinkedQueue<>();
+        for (int i = 0; i < n; i++) {
+            connPool.getSession(target, TIMEOUT, new FutureCallback<IOSession>() {
+
+                @Override
+                public void completed(final IOSession session) {
+                    latch.countDown();
+                }
+
+                @Override
+                public void failed(final Exception ex) {
+                    latch.countDown();
+                }
+
+                @Override
+                public void cancelled() {
+                    latch.countDown();
+                }
+
+            });
+        }
+
+        requester.initiateShutdown();
+        requester.awaitShutdown(TIMEOUT);
+
+        Assertions.assertEquals(0, clientConnCount.get());
+    }
+
+}
diff --git a/httpcore5/pom.xml b/httpcore5/pom.xml
index f9b341c..9bc23e9 100644
--- a/httpcore5/pom.xml
+++ b/httpcore5/pom.xml
@@ -28,7 +28,7 @@
   <parent>
     <groupId>org.apache.httpcomponents.core5</groupId>
     <artifactId>httpcore5-parent</artifactId>
-    <version>5.2.1</version>
+    <version>5.2.2</version>
   </parent>
   <artifactId>httpcore5</artifactId>
   <name>Apache HttpComponents Core HTTP/1.1</name>
diff --git a/httpcore5/src/main/java/org/apache/hc/core5/http/ContentType.java b/httpcore5/src/main/java/org/apache/hc/core5/http/ContentType.java
index 4fae21c..938fc10 100644
--- a/httpcore5/src/main/java/org/apache/hc/core5/http/ContentType.java
+++ b/httpcore5/src/main/java/org/apache/hc/core5/http/ContentType.java
@@ -387,7 +387,7 @@ public final class ContentType implements Serializable {
             final String mimeType, final NameValuePair... params) throws UnsupportedCharsetException {
         final String type = TextUtils.toLowerCase(Args.notBlank(mimeType, "MIME type"));
         Args.check(valid(type), "MIME type may not contain reserved characters");
-        return create(mimeType, params, true);
+        return create(mimeType, params != null ? params.clone() : null, true);
     }
 
     /**
@@ -483,7 +483,7 @@ public final class ContentType implements Serializable {
     /**
      * Creates a new instance with this MIME type and the given parameters.
      *
-     * @param params
+     * @param params parameters.
      * @return a new instance with this MIME type and the given parameters.
      * @since 4.4
      */
diff --git a/httpcore5/src/main/java/org/apache/hc/core5/http/message/AbstractMessageWrapper.java b/httpcore5/src/main/java/org/apache/hc/core5/http/message/AbstractMessageWrapper.java
index 16604d8..665a872 100644
--- a/httpcore5/src/main/java/org/apache/hc/core5/http/message/AbstractMessageWrapper.java
+++ b/httpcore5/src/main/java/org/apache/hc/core5/http/message/AbstractMessageWrapper.java
@@ -37,12 +37,14 @@ import org.apache.hc.core5.util.Args;
 
 /**
  * Abstract {@link HttpMessage} wrapper.
+ *
+ * @param <T> A {@link HttpMessage} type.
  */
-public abstract class AbstractMessageWrapper implements HttpMessage {
+public abstract class AbstractMessageWrapper<T extends HttpMessage> implements HttpMessage {
 
-    private final HttpMessage message;
+    private final T message;
 
-    public AbstractMessageWrapper(final HttpMessage message) {
+    public AbstractMessageWrapper(final T message) {
         this.message = Args.notNull(message, "Message");
     }
 
@@ -121,6 +123,10 @@ public abstract class AbstractMessageWrapper implements HttpMessage {
         return message.getLastHeader(name);
     }
 
+    T getMessage() {
+        return message;
+    }
+
     @Override
     public Header[] getHeaders() {
         return message.getHeaders();
diff --git a/httpcore5/src/main/java/org/apache/hc/core5/http/message/BasicHttpRequest.java b/httpcore5/src/main/java/org/apache/hc/core5/http/message/BasicHttpRequest.java
index 5b1db70..0d4279e 100644
--- a/httpcore5/src/main/java/org/apache/hc/core5/http/message/BasicHttpRequest.java
+++ b/httpcore5/src/main/java/org/apache/hc/core5/http/message/BasicHttpRequest.java
@@ -27,6 +27,9 @@
 
 package org.apache.hc.core5.http.message;
 
+import java.net.URI;
+import java.net.URISyntaxException;
+
 import org.apache.hc.core5.http.HttpHost;
 import org.apache.hc.core5.http.HttpRequest;
 import org.apache.hc.core5.http.Method;
@@ -36,9 +39,6 @@ import org.apache.hc.core5.net.URIAuthority;
 import org.apache.hc.core5.util.Args;
 import org.apache.hc.core5.util.TextUtils;
 
-import java.net.URI;
-import java.net.URISyntaxException;
-
 /**
  * Basic implementation of {@link HttpRequest}.
  *
@@ -288,6 +288,7 @@ public class BasicHttpRequest extends HeaderGroup implements HttpRequest {
             buf.append('?').append(query);
         }
         this.path = buf.toString();
+        this.requestUri = null;
     }
 
     private void assembleRequestUri(final StringBuilder buf) {
diff --git a/httpcore5/src/main/java/org/apache/hc/core5/http/message/HttpRequestWrapper.java b/httpcore5/src/main/java/org/apache/hc/core5/http/message/HttpRequestWrapper.java
index 75a6af8..4535422 100644
--- a/httpcore5/src/main/java/org/apache/hc/core5/http/message/HttpRequestWrapper.java
+++ b/httpcore5/src/main/java/org/apache/hc/core5/http/message/HttpRequestWrapper.java
@@ -34,65 +34,64 @@ import org.apache.hc.core5.http.HttpRequest;
 import org.apache.hc.core5.net.URIAuthority;
 
 /**
+ * Wraps an {@link HttpRequest}.
+ *
  * {@link HttpRequest} wrapper.
  */
-public class HttpRequestWrapper extends AbstractMessageWrapper implements HttpRequest {
-
-    private final HttpRequest message;
+public class HttpRequestWrapper extends AbstractMessageWrapper<HttpRequest> implements HttpRequest {
 
     public HttpRequestWrapper(final HttpRequest message) {
         super(message);
-        this.message = message;
     }
 
     @Override
     public String getMethod() {
-        return message.getMethod();
+        return getMessage().getMethod();
     }
 
     @Override
     public String getPath() {
-        return message.getPath();
+        return getMessage().getPath();
     }
 
     @Override
     public void setPath(final String path) {
-        message.setPath(path);
+        getMessage().setPath(path);
     }
 
     @Override
     public String getScheme() {
-        return message.getScheme();
+        return getMessage().getScheme();
     }
 
     @Override
     public void setScheme(final String scheme) {
-        message.setScheme(scheme);
+        getMessage().setScheme(scheme);
     }
 
     @Override
     public URIAuthority getAuthority() {
-        return message.getAuthority();
+        return getMessage().getAuthority();
     }
 
     @Override
     public void setAuthority(final URIAuthority authority) {
-        message.setAuthority(authority);
+        getMessage().setAuthority(authority);
     }
 
     @Override
     public String getRequestUri() {
-        return message.getRequestUri();
+        return getMessage().getRequestUri();
     }
 
     @Override
     public URI getUri() throws URISyntaxException {
-        return message.getUri();
+        return getMessage().getUri();
     }
 
     @Override
     public void setUri(final URI requestUri) {
-        message.setUri(requestUri);
+        getMessage().setUri(requestUri);
     }
 
 }
diff --git a/httpcore5/src/main/java/org/apache/hc/core5/http/message/HttpResponseWrapper.java b/httpcore5/src/main/java/org/apache/hc/core5/http/message/HttpResponseWrapper.java
index 01ee2e8..6826ce0 100644
--- a/httpcore5/src/main/java/org/apache/hc/core5/http/message/HttpResponseWrapper.java
+++ b/httpcore5/src/main/java/org/apache/hc/core5/http/message/HttpResponseWrapper.java
@@ -32,45 +32,44 @@ import java.util.Locale;
 import org.apache.hc.core5.http.HttpResponse;
 
 /**
+ * Wraps an {@link HttpResponse}.
+ *
  * {@link HttpResponse} wrapper.
  */
-public class HttpResponseWrapper extends AbstractMessageWrapper implements HttpResponse {
-
-    private final HttpResponse message;
+public class HttpResponseWrapper extends AbstractMessageWrapper<HttpResponse> implements HttpResponse {
 
     public HttpResponseWrapper(final HttpResponse message) {
         super(message);
-        this.message = message;
     }
 
     @Override
     public int getCode() {
-        return message.getCode();
+        return getMessage().getCode();
     }
 
     @Override
     public void setCode(final int code) {
-        message.setCode(code);
+        getMessage().setCode(code);
     }
 
     @Override
     public String getReasonPhrase() {
-        return message.getReasonPhrase();
+        return getMessage().getReasonPhrase();
     }
 
     @Override
     public void setReasonPhrase(final String reason) {
-        message.setReasonPhrase(reason);
+        getMessage().setReasonPhrase(reason);
     }
 
     @Override
     public Locale getLocale() {
-        return message.getLocale();
+        return getMessage().getLocale();
     }
 
     @Override
     public void setLocale(final Locale loc) {
-        message.setLocale(loc);
+        getMessage().setLocale(loc);
     }
 
 }
diff --git a/httpcore5/src/main/java/org/apache/hc/core5/http/nio/entity/BasicAsyncEntityProducer.java b/httpcore5/src/main/java/org/apache/hc/core5/http/nio/entity/BasicAsyncEntityProducer.java
index 9bb55c2..0a2bb6d 100644
--- a/httpcore5/src/main/java/org/apache/hc/core5/http/nio/entity/BasicAsyncEntityProducer.java
+++ b/httpcore5/src/main/java/org/apache/hc/core5/http/nio/entity/BasicAsyncEntityProducer.java
@@ -147,6 +147,7 @@ public class BasicAsyncEntityProducer implements AsyncEntityProducer {
     @Override
     public void releaseResources() {
         bytebuf.clear();
+        bytebuf.limit(length);
     }
 
 }
diff --git a/httpcore5/src/main/java/org/apache/hc/core5/reactor/AbstractIOSessionPool.java b/httpcore5/src/main/java/org/apache/hc/core5/reactor/AbstractIOSessionPool.java
index efe855d..339d4ee 100644
--- a/httpcore5/src/main/java/org/apache/hc/core5/reactor/AbstractIOSessionPool.java
+++ b/httpcore5/src/main/java/org/apache/hc/core5/reactor/AbstractIOSessionPool.java
@@ -182,10 +182,11 @@ public abstract class AbstractIOSessionPool<T> implements ModalCloseable {
                 callback.completed(poolEntry.session);
             } else {
                 poolEntry.requestQueue.add(callback);
-                if (poolEntry.sessionFuture != null && poolEntry.sessionFuture.isDone()) {
+                if (poolEntry.sessionFuture != null && poolEntry.completed) {
                     poolEntry.sessionFuture = null;
                 }
                 if (poolEntry.sessionFuture == null) {
+                    poolEntry.completed = false;
                     poolEntry.sessionFuture = connectSession(
                             namedEndpoint,
                             connectTimeout,
@@ -194,7 +195,12 @@ public abstract class AbstractIOSessionPool<T> implements ModalCloseable {
                                 @Override
                                 public void completed(final IOSession result) {
                                     synchronized (poolEntry) {
-                                        poolEntry.session = result;
+                                        poolEntry.completed = true;
+                                        if (poolEntry.session == null) {
+                                            poolEntry.session = result;
+                                        } else {
+                                            closeSession(result,CloseMode.GRACEFUL);
+                                        }
                                         for (;;) {
                                             final FutureCallback<IOSession> callback = poolEntry.requestQueue.poll();
                                             if (callback != null) {
@@ -209,6 +215,7 @@ public abstract class AbstractIOSessionPool<T> implements ModalCloseable {
                                 @Override
                                 public void failed(final Exception ex) {
                                     synchronized (poolEntry) {
+                                        poolEntry.completed = true;
                                         poolEntry.session = null;
                                         for (;;) {
                                             final FutureCallback<IOSession> callback = poolEntry.requestQueue.poll();
@@ -276,6 +283,7 @@ public abstract class AbstractIOSessionPool<T> implements ModalCloseable {
     static class PoolEntry {
 
         final Queue<FutureCallback<IOSession>> requestQueue;
+        volatile boolean completed;
         volatile Future<IOSession> sessionFuture;
         volatile IOSession session;
 
diff --git a/httpcore5/src/main/java/org/apache/hc/core5/reactor/SingleCoreIOReactor.java b/httpcore5/src/main/java/org/apache/hc/core5/reactor/SingleCoreIOReactor.java
index 248ce10..a9c9365 100644
--- a/httpcore5/src/main/java/org/apache/hc/core5/reactor/SingleCoreIOReactor.java
+++ b/httpcore5/src/main/java/org/apache/hc/core5/reactor/SingleCoreIOReactor.java
@@ -214,8 +214,8 @@ class SingleCoreIOReactor extends AbstractSingleCoreIOReactor implements Connect
                     ioSessionDecorator,
                     sessionListener,
                     closedSessions);
-            dataChannel.upgrade(this.eventHandlerFactory.createHandler(dataChannel, attachment));
             dataChannel.setSocketTimeout(this.reactorConfig.getSoTimeout());
+            dataChannel.upgrade(this.eventHandlerFactory.createHandler(dataChannel, attachment));
             key.attach(dataChannel);
             dataChannel.handleIOEvent(SelectionKey.OP_CONNECT);
         }
diff --git a/httpcore5/src/main/java/org/apache/hc/core5/reactor/ssl/SSLIOSession.java b/httpcore5/src/main/java/org/apache/hc/core5/reactor/ssl/SSLIOSession.java
index 5e5210e..ae0c188 100644
--- a/httpcore5/src/main/java/org/apache/hc/core5/reactor/ssl/SSLIOSession.java
+++ b/httpcore5/src/main/java/org/apache/hc/core5/reactor/ssl/SSLIOSession.java
@@ -424,9 +424,18 @@ public class SSLIOSession implements IOSession {
             if (this.verifier != null) {
                 this.tlsDetails = this.verifier.verify(this.targetEndpoint, this.sslEngine);
             }
+            String applicationProtocol;
             if (this.tlsDetails == null) {
                 final SSLSession sslSession = this.sslEngine.getSession();
-                final String applicationProtocol = this.sslEngine.getApplicationProtocol();
+                try {
+                    applicationProtocol = this.sslEngine.getApplicationProtocol();
+                } catch (final UnsupportedOperationException e) {
+                    // If the underlying provider does not support the operation, the getApplicationProtocol() method throws an UnsupportedOperationException.
+                    // In this case, we fall back to "http/1.1" as the application protocol.
+                    // This is a workaround to allow older applications that do not support the getApplicationProtocol() method to continue working.
+                    // This workaround is temporary and is meant to maintain compatibility with older systems.
+                    applicationProtocol = "http/1.1";
+                }
                 this.tlsDetails = new TlsDetails(sslSession, applicationProtocol);
             }
 
diff --git a/httpcore5/src/test/java/org/apache/hc/core5/http/TestContentType.java b/httpcore5/src/test/java/org/apache/hc/core5/http/TestContentType.java
index 8a0b01f..d4f7e9f 100644
--- a/httpcore5/src/test/java/org/apache/hc/core5/http/TestContentType.java
+++ b/httpcore5/src/test/java/org/apache/hc/core5/http/TestContentType.java
@@ -28,6 +28,7 @@
 package org.apache.hc.core5.http;
 
 import java.nio.charset.StandardCharsets;
+import java.util.Arrays;
 
 import org.apache.hc.core5.http.message.BasicNameValuePair;
 import org.junit.jupiter.api.Assertions;
@@ -136,6 +137,22 @@ public class TestContentType {
         Assertions.assertNull(ContentType.parse("="));
     }
 
+    @Test
+    public void testWithParamArrayChange() throws Exception {
+        final BasicNameValuePair[] params = {new BasicNameValuePair("charset", "UTF-8"),
+                new BasicNameValuePair("p", "this"),
+                new BasicNameValuePair("p", "that")};
+        final ContentType contentType = ContentType.create("text/plain", params);
+        Assertions.assertEquals("text/plain", contentType.getMimeType());
+        Assertions.assertEquals(StandardCharsets.UTF_8, contentType.getCharset());
+        Assertions.assertEquals("text/plain; charset=UTF-8; p=this; p=that", contentType.toString());
+        Arrays.setAll(params, i -> null);
+        Assertions.assertEquals("this", contentType.getParameter("p"));
+        Assertions.assertEquals("text/plain", contentType.getMimeType());
+        Assertions.assertEquals(StandardCharsets.UTF_8, contentType.getCharset());
+        Assertions.assertEquals("text/plain; charset=UTF-8; p=this; p=that", contentType.toString());
+    }
+
     @Test
     public void testWithParams() throws Exception {
         ContentType contentType = ContentType.create("text/plain",
diff --git a/httpcore5/src/test/java/org/apache/hc/core5/http/examples/ClassicPostExecutionExample.java b/httpcore5/src/test/java/org/apache/hc/core5/http/examples/ClassicPostExecutionExample.java
index fa79ae6..e574def 100644
--- a/httpcore5/src/test/java/org/apache/hc/core5/http/examples/ClassicPostExecutionExample.java
+++ b/httpcore5/src/test/java/org/apache/hc/core5/http/examples/ClassicPostExecutionExample.java
@@ -106,7 +106,7 @@ public class ClassicPostExecutionExample {
 
         final String requestUri = "/post";
         for (int i = 0; i < requestBodies.length; i++) {
-            final ClassicHttpRequest request = ClassicRequestBuilder.get()
+            final ClassicHttpRequest request = ClassicRequestBuilder.post()
                     .setHttpHost(target)
                     .setPath(requestUri)
                     .build();
diff --git a/httpcore5/src/test/java/org/apache/hc/core5/http/message/TestBasicMessages.java b/httpcore5/src/test/java/org/apache/hc/core5/http/message/TestBasicMessages.java
index cf84036..54a0095 100644
--- a/httpcore5/src/test/java/org/apache/hc/core5/http/message/TestBasicMessages.java
+++ b/httpcore5/src/test/java/org/apache/hc/core5/http/message/TestBasicMessages.java
@@ -35,6 +35,7 @@ import org.apache.hc.core5.http.HttpResponse;
 import org.apache.hc.core5.http.HttpStatus;
 import org.apache.hc.core5.http.Method;
 import org.apache.hc.core5.net.URIAuthority;
+import org.apache.hc.core5.net.URIBuilder;
 import org.junit.jupiter.api.Assertions;
 import org.junit.jupiter.api.Test;
 
@@ -211,5 +212,18 @@ public class TestBasicMessages {
         Assertions.assertEquals("http://somehost/stuff", request.getRequestUri());
     }
 
+    @Test
+    public void testModifyingExistingRequest() throws Exception {
+        final URI uri = URI.create("https://example.org");
+        final HttpRequest request = new BasicHttpRequest(Method.GET, uri);
+
+        final URI newUri = new URIBuilder(request.getUri())
+                .addParameter("name", "value")
+                .build();
+
+        request.setUri(newUri);
+        Assertions.assertEquals(newUri, request.getUri());
+    }
+
 }
 
diff --git a/httpcore5/src/test/java/org/apache/hc/core5/http/nio/entity/TestBasicAsyncEntityProducer.java b/httpcore5/src/test/java/org/apache/hc/core5/http/nio/entity/TestBasicAsyncEntityProducer.java
index d2fa09a..072e13e 100644
--- a/httpcore5/src/test/java/org/apache/hc/core5/http/nio/entity/TestBasicAsyncEntityProducer.java
+++ b/httpcore5/src/test/java/org/apache/hc/core5/http/nio/entity/TestBasicAsyncEntityProducer.java
@@ -99,4 +99,18 @@ public class TestBasicAsyncEntityProducer {
         }
     }
 
+    @Test
+    public void testTextContentRepeatableUTF() throws Exception {
+        final String content = "<testtag></testtag>";
+        final AsyncEntityProducer producer = new BasicAsyncEntityProducer(content, ContentType.TEXT_XML);
+        for (int i = 0; i < 3; i++) {
+            final WritableByteChannelMock byteChannel = new WritableByteChannelMock(1024);
+            final DataStreamChannel streamChannel = new BasicDataStreamChannel(byteChannel);
+            producer.produce(streamChannel);
+            Assertions.assertFalse(byteChannel.isOpen());
+            Assertions.assertEquals(content, byteChannel.dump(StandardCharsets.UTF_8));
+            producer.releaseResources();
+        }
+    }
+
 }
diff --git a/httpcore5/src/test/java/org/apache/hc/core5/reactor/ssl/SSLIOSessionTest.java b/httpcore5/src/test/java/org/apache/hc/core5/reactor/ssl/SSLIOSessionTest.java
new file mode 100644
index 0000000..290434f
--- /dev/null
+++ b/httpcore5/src/test/java/org/apache/hc/core5/reactor/ssl/SSLIOSessionTest.java
@@ -0,0 +1,183 @@
+/*
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation.  For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+package org.apache.hc.core5.reactor.ssl;
+
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.mock;
+
+import java.nio.ByteBuffer;
+import java.security.Provider;
+import java.util.concurrent.locks.ReentrantLock;
+
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLContextSpi;
+import javax.net.ssl.SSLEngine;
+import javax.net.ssl.SSLEngineResult;
+import javax.net.ssl.SSLException;
+import javax.net.ssl.SSLSession;
+
+import org.apache.hc.core5.concurrent.FutureCallback;
+import org.apache.hc.core5.function.Callback;
+import org.apache.hc.core5.net.NamedEndpoint;
+import org.apache.hc.core5.reactor.IOEventHandler;
+import org.apache.hc.core5.reactor.IOSession;
+import org.apache.hc.core5.util.Timeout;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.mockito.Mockito;
+
+class SSLIOSessionTest {
+
+    // Define common variables here, so you can easily modify them in each test
+    private NamedEndpoint targetEndpoint;
+    private IOSession ioSession;
+    private SSLMode sslMode;
+    private SSLContext sslContext;
+    private SSLBufferMode sslBufferMode;
+    private SSLSessionInitializer initializer;
+    private SSLSessionVerifier verifier;
+    private Timeout handshakeTimeout;
+    private Callback<SSLIOSession> sessionStartCallback;
+    private Callback<SSLIOSession> sessionEndCallback;
+    private FutureCallback<SSLSession> resultCallback;
+    private IOEventHandler ioEventHandler;
+    private SSLEngine mockSSLEngine;
+    private SSLSession sslSession;
+
+    @BeforeEach
+    public void setUp() throws SSLException {
+        final String protocol = "TestProtocol";
+
+        // Arrange
+        targetEndpoint = mock(NamedEndpoint.class);
+        ioSession = mock(IOSession.class);
+        sslMode = SSLMode.CLIENT;  // Use actual SSLMode
+
+        //SSLContext sslContext = SSLContext.getDefault();
+        final SSLContextSpi sslContextSpi = mock(SSLContextSpi.class);
+        final Provider provider = mock(Provider.class);
+        sslContext = new TestSSLContext(sslContextSpi, provider, protocol);
+
+        sslSession = mock(SSLSession.class);
+
+        sslBufferMode = SSLBufferMode.STATIC;
+        initializer = mock(SSLSessionInitializer.class);
+        verifier = mock(SSLSessionVerifier.class);
+        handshakeTimeout = mock(Timeout.class);
+        sessionStartCallback = mock(Callback.class);
+        sessionEndCallback = mock(Callback.class);
+        resultCallback = mock(FutureCallback.class);
+        ioEventHandler = mock(IOEventHandler.class);
+
+        // Mock behavior of targetEndpoint
+        Mockito.when(targetEndpoint.getHostName()).thenReturn("testHostName");
+        Mockito.when(targetEndpoint.getPort()).thenReturn(8080);
+
+        Mockito.when(sslSession.getPacketBufferSize()).thenReturn(1024);
+        Mockito.when(sslSession.getApplicationBufferSize()).thenReturn(1024);
+
+        // Mock behavior of ioSession
+        Mockito.when(ioSession.getEventMask()).thenReturn(1);
+        Mockito.when(ioSession.getLock()).thenReturn(new ReentrantLock());
+
+        // Mock behavior of sslContext and SSLEngine
+        mockSSLEngine = mock(SSLEngine.class);
+        Mockito.when(sslContext.createSSLEngine(any(String.class), any(Integer.class))).thenReturn(mockSSLEngine);
+        Mockito.when(mockSSLEngine.getSession()).thenReturn(sslSession);
+        Mockito.when(mockSSLEngine.getHandshakeStatus()).thenReturn(SSLEngineResult.HandshakeStatus.NEED_WRAP);
+
+        Mockito.when(ioSession.getHandler()).thenReturn(ioEventHandler);
+
+        final SSLEngineResult mockResult = new SSLEngineResult(SSLEngineResult.Status.CLOSED,
+                SSLEngineResult.HandshakeStatus.FINISHED,
+                0, 464);
+        Mockito.when(mockSSLEngine.wrap(any(ByteBuffer.class), any(ByteBuffer.class))).thenReturn(mockResult);
+    }
+
+
+    @Test
+    void testConstructorWhenSSLEngineOk() {
+        final String protocol = "TestProtocol";
+        // Arrange
+        Mockito.when(mockSSLEngine.getApplicationProtocol()).thenReturn(protocol);
+
+        // Act
+        final TestableSSLIOSession sslioSession = new TestableSSLIOSession(targetEndpoint, ioSession, sslMode, sslContext,
+                sslBufferMode, initializer, verifier, handshakeTimeout, sessionStartCallback, sessionEndCallback,
+                resultCallback);
+
+        // Assert
+        Assertions.assertDoesNotThrow(() -> sslioSession.beginHandshake(ioSession));
+        Assertions.assertEquals(protocol, sslioSession.getTlsDetails().getApplicationProtocol());
+    }
+
+    @Test
+    void testConstructorWhenSSLEngineThrowsException() {
+        final String protocol = "http/1.1";
+        // Arrange
+        Mockito.when(mockSSLEngine.getApplicationProtocol()).thenThrow(UnsupportedOperationException.class);
+
+        // Act
+        final TestableSSLIOSession sslioSession = new TestableSSLIOSession(targetEndpoint, ioSession, sslMode, sslContext,
+                sslBufferMode, initializer, verifier, handshakeTimeout, sessionStartCallback, sessionEndCallback,
+                resultCallback);
+
+        // Assert
+        Assertions.assertDoesNotThrow(() -> sslioSession.beginHandshake(ioSession));
+        Assertions.assertEquals(protocol, sslioSession.getTlsDetails().getApplicationProtocol());
+    }
+
+
+    static class TestSSLContext extends SSLContext {
+
+        /**
+         * Creates an SSLContext object.
+         *
+         * @param contextSpi the delegate
+         * @param provider   the provider
+         * @param protocol   the protocol
+         */
+        protected TestSSLContext(final SSLContextSpi contextSpi, final Provider provider, final String protocol) {
+            super(contextSpi, provider, protocol);
+        }
+    }
+
+    static class TestableSSLIOSession extends SSLIOSession {
+        TestableSSLIOSession(final NamedEndpoint targetEndpoint, final IOSession session, final SSLMode sslMode, final SSLContext sslContext,
+                             final SSLBufferMode sslBufferMode, final SSLSessionInitializer initializer, final SSLSessionVerifier verifier,
+                             final Timeout handshakeTimeout, final Callback<SSLIOSession> sessionStartCallback,
+                             final Callback<SSLIOSession> sessionEndCallback, final FutureCallback<SSLSession> resultCallback) {
+            super(targetEndpoint, session, sslMode, sslContext, sslBufferMode, initializer, verifier,
+                    handshakeTimeout, sessionStartCallback, sessionEndCallback, resultCallback);
+        }
+    }
+
+}
+
+
diff --git a/pom.xml b/pom.xml
index b193b49..9fd7052 100644
--- a/pom.xml
+++ b/pom.xml
@@ -33,7 +33,7 @@
   <groupId>org.apache.httpcomponents.core5</groupId>
   <artifactId>httpcore5-parent</artifactId>
   <name>Apache HttpComponents Core Parent</name>
-  <version>5.2.1</version>
+  <version>5.2.2</version>
   <description>Apache HttpComponents Core is a library of components for building HTTP enabled services</description>
   <url>https://hc.apache.org/httpcomponents-core-5.2.x/${project.version}/</url>
   <inceptionYear>2005</inceptionYear>
@@ -48,7 +48,7 @@
     <connection>scm:git:https://gitbox.apache.org/repos/asf/httpcomponents-core.git</connection>
     <developerConnection>scm:git:https://gitbox.apache.org/repos/asf/httpcomponents-core.git</developerConnection>
     <url>https://github.com/apache/httpcomponents-core/tree/${project.scm.tag}</url>
-    <tag>5.2.1</tag>
+    <tag>5.2.2</tag>
   </scm>
 
   <distributionManagement>
@@ -72,15 +72,15 @@
     <maven.compiler.target>1.8</maven.compiler.target>
     <maven.compiler.showDeprecation>true</maven.compiler.showDeprecation>
     <conscrypt.version>2.5.2</conscrypt.version>
-    <junit.version>5.9.1</junit.version>
+    <junit.version>5.9.3</junit.version>
     <hamcrest.version>2.2</hamcrest.version>
     <junit.migrationsupport.version>5.0.0</junit.migrationsupport.version>
     <mockito.version>4.11.0</mockito.version>
     <slf4j.version>1.7.36</slf4j.version>
     <log4j.version>2.19.0</log4j.version>
     <rxjava.version>2.2.21</rxjava.version>
-    <rxjava3.version>3.1.5</rxjava3.version>
-    <api.comparison.version>5.1</api.comparison.version>
+    <rxjava3.version>3.1.6</rxjava3.version>
+    <api.comparison.version>5.2</api.comparison.version>
     <hc.animal-sniffer.signature.ignores>javax.net.ssl.SSLEngine,javax.net.ssl.SSLParameters,java.nio.ByteBuffer,java.nio.CharBuffer</hc.animal-sniffer.signature.ignores>
   </properties>
 

Debdiff

[The following lists of changes regard files as different if they have different names, permissions or owners.]

Files in second set of .debs but not in first

-rw-r--r--  root/root   /usr/share/java/httpcore5-5.2.2.jar
-rw-r--r--  root/root   /usr/share/java/httpcore5-h2-5.2.2.jar
-rw-r--r--  root/root   /usr/share/maven-repo/org/apache/httpcomponents/core5/httpcore5-h2/5.2.2/httpcore5-h2-5.2.2.pom
-rw-r--r--  root/root   /usr/share/maven-repo/org/apache/httpcomponents/core5/httpcore5-parent/5.2.2/httpcore5-parent-5.2.2.pom
-rw-r--r--  root/root   /usr/share/maven-repo/org/apache/httpcomponents/core5/httpcore5/5.2.2/httpcore5-5.2.2.pom
lrwxrwxrwx  root/root   /usr/share/java/httpcore5-h2.jar -> httpcore5-h2-5.2.2.jar
lrwxrwxrwx  root/root   /usr/share/java/httpcore5.jar -> httpcore5-5.2.2.jar
lrwxrwxrwx  root/root   /usr/share/maven-repo/org/apache/httpcomponents/core5/httpcore5-h2/5.2.2/httpcore5-h2-5.2.2.jar -> ../../../../../../../java/httpcore5-h2-5.2.2.jar
lrwxrwxrwx  root/root   /usr/share/maven-repo/org/apache/httpcomponents/core5/httpcore5-h2/debian/httpcore5-h2-debian.jar -> ../../../../../../../java/httpcore5-h2-5.2.2.jar
lrwxrwxrwx  root/root   /usr/share/maven-repo/org/apache/httpcomponents/core5/httpcore5/5.2.2/httpcore5-5.2.2.jar -> ../../../../../../../java/httpcore5-5.2.2.jar
lrwxrwxrwx  root/root   /usr/share/maven-repo/org/apache/httpcomponents/core5/httpcore5/debian/httpcore5-debian.jar -> ../../../../../../../java/httpcore5-5.2.2.jar

Files in first set of .debs but not in second

-rw-r--r--  root/root   /usr/share/java/httpcore5-h2.jar
-rw-r--r--  root/root   /usr/share/java/httpcore5.jar
-rw-r--r--  root/root   /usr/share/maven-repo/org/apache/httpcomponents/core5/httpcore5-h2/5.2.1/httpcore5-h2-5.2.1.pom
-rw-r--r--  root/root   /usr/share/maven-repo/org/apache/httpcomponents/core5/httpcore5-parent/5.2.1/httpcore5-parent-5.2.1.pom
-rw-r--r--  root/root   /usr/share/maven-repo/org/apache/httpcomponents/core5/httpcore5/5.2.1/httpcore5-5.2.1.pom
lrwxrwxrwx  root/root   /usr/share/java/httpcore5-5.2.1.jar -> httpcore5.jar
lrwxrwxrwx  root/root   /usr/share/java/httpcore5-h2-5.2.1.jar -> httpcore5-h2.jar
lrwxrwxrwx  root/root   /usr/share/maven-repo/org/apache/httpcomponents/core5/httpcore5-h2/5.2.1/httpcore5-h2-5.2.1.jar -> ../../../../../../../java/httpcore5-h2.jar
lrwxrwxrwx  root/root   /usr/share/maven-repo/org/apache/httpcomponents/core5/httpcore5-h2/debian/httpcore5-h2-debian.jar -> ../../../../../../../java/httpcore5-h2.jar
lrwxrwxrwx  root/root   /usr/share/maven-repo/org/apache/httpcomponents/core5/httpcore5/5.2.1/httpcore5-5.2.1.jar -> ../../../../../../../java/httpcore5.jar
lrwxrwxrwx  root/root   /usr/share/maven-repo/org/apache/httpcomponents/core5/httpcore5/debian/httpcore5-debian.jar -> ../../../../../../../java/httpcore5.jar

No differences were encountered in the control files

More details

Full run details