[Git][java-team/httpcomponents-core5][upstream] New upstream version 5.4.4

Emmanuel Bourg (@ebourg) gitlab at salsa.debian.org
Fri Sep 25 19:39:46 BST 2026



Emmanuel Bourg pushed to branch upstream at Debian Java Maintainers / httpcomponents-core5


Commits:
d3056127 by Emmanuel Bourg at 2026-09-25T19:17:32+02:00
New upstream version 5.4.4
- - - - -


22 changed files:

- RELEASE_NOTES.txt
- httpcore5-h2/pom.xml
- httpcore5-reactive/pom.xml
- httpcore5-testing/pom.xml
- + httpcore5-testing/src/test/java/org/apache/hc/core5/benchmark/Http1BufferSizeBenchmark.java
- httpcore5/pom.xml
- httpcore5/src/main/java/org/apache/hc/core5/http/HttpException.java
- httpcore5/src/main/java/org/apache/hc/core5/http/config/Http1Config.java
- httpcore5/src/main/java/org/apache/hc/core5/http/nio/entity/AbstractBinAsyncEntityProducer.java
- httpcore5/src/main/java/org/apache/hc/core5/http/nio/entity/AbstractCharAsyncEntityProducer.java
- httpcore5/src/main/java/org/apache/hc/core5/http/nio/entity/DigestingEntityProducer.java
- httpcore5/src/main/java/org/apache/hc/core5/http/nio/entity/FileEntityProducer.java
- httpcore5/src/main/java/org/apache/hc/core5/http/nio/entity/PathEntityProducer.java
- httpcore5/src/main/java/org/apache/hc/core5/net/URIBuilder.java
- httpcore5/src/test/java/org/apache/hc/core5/http/TestHttpExceptions.java
- httpcore5/src/test/java/org/apache/hc/core5/http/nio/entity/TestAbstractBinAsyncEntityProducer.java
- httpcore5/src/test/java/org/apache/hc/core5/http/nio/entity/TestDigestingEntityProducer.java
- httpcore5/src/test/java/org/apache/hc/core5/http/nio/entity/TestFileAsyncEntityProducer.java
- httpcore5/src/test/java/org/apache/hc/core5/http/nio/entity/TestPathAsyncEntityProducer.java
- httpcore5/src/test/java/org/apache/hc/core5/http/nio/entity/TestStringAsyncEntityProducer.java
- httpcore5/src/test/java/org/apache/hc/core5/net/TestURIBuilder.java
- pom.xml


Changes:

=====================================
RELEASE_NOTES.txt
=====================================
@@ -1,3 +1,26 @@
+Release 5.4.4
+------------------
+
+This maintenance release optimizes HTTP/1.1 message buffer configuration and corrects
+the handling of asynchronous entity producer state resets after interrupted writes.
+
+
+Change Log
+-------------------
+
+* HTTPCORE-800: Fixed hexadecimal encoding of control characters in HttpException messages.
+  Contributed by Arturo Bernal <abernal at apache.org>
+
+* HTTPCORE-799: Corrected the handling of asynchronous entity producer state resets after interrupted writes.
+  Contributed by Matthias Kurz <m.kurz at irregular.at>
+
+* Fixed URIBuilder encoding policy documentation and null reset behavior.
+  Contributed by Praful Gupta <prafulgupta6 at gmail.com>
+
+* Increased the default HTTP/1.1 buffer size to 32 KiB.
+  Contributed by Arturo Bernal <abernal at apache.org>
+
+
 Release 5.4.3
 ------------------
 
@@ -16,7 +39,7 @@ Change Log
   Contributed by Ryan Schmitt <rschmitt at apache.org>
 
 * Use max line length of 8192 and max header count of 100 for incoming HTTP/1 messages
-  by default.
+  by default. Override with Http1Config.Builder.setMaxLineLength(int) and setMaxHeaderCount(int).
   Contributed by Oleg Kalnichevski <olegk at apache.org>
 
 * Enforce configured HPACK header list size limit upon initialization of HTTP/2


=====================================
httpcore5-h2/pom.xml
=====================================
@@ -28,7 +28,7 @@
   <parent>
     <groupId>org.apache.httpcomponents.core5</groupId>
     <artifactId>httpcore5-parent</artifactId>
-    <version>5.4.3</version>
+    <version>5.4.4</version>
   </parent>
   <artifactId>httpcore5-h2</artifactId>
   <name>Apache HttpComponents Core HTTP/2</name>


=====================================
httpcore5-reactive/pom.xml
=====================================
@@ -27,7 +27,7 @@
   <parent>
     <artifactId>httpcore5-parent</artifactId>
     <groupId>org.apache.httpcomponents.core5</groupId>
-    <version>5.4.3</version>
+    <version>5.4.4</version>
   </parent>
   <modelVersion>4.0.0</modelVersion>
 


=====================================
httpcore5-testing/pom.xml
=====================================
@@ -28,7 +28,7 @@
   <parent>
     <groupId>org.apache.httpcomponents.core5</groupId>
     <artifactId>httpcore5-parent</artifactId>
-    <version>5.4.3</version>
+    <version>5.4.4</version>
   </parent>
   <artifactId>httpcore5-testing</artifactId>
   <name>Apache HttpComponents Core Integration Tests</name>


=====================================
httpcore5-testing/src/test/java/org/apache/hc/core5/benchmark/Http1BufferSizeBenchmark.java
=====================================
@@ -0,0 +1,161 @@
+/*
+ * ====================================================================
+ * 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.benchmark;
+
+import java.net.InetSocketAddress;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+
+import org.apache.hc.core5.http.ContentType;
+import org.apache.hc.core5.http.EntityDetails;
+import org.apache.hc.core5.http.HttpException;
+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.HttpStatus;
+import org.apache.hc.core5.http.Message;
+import org.apache.hc.core5.http.Method;
+import org.apache.hc.core5.http.config.Http1Config;
+import org.apache.hc.core5.http.impl.bootstrap.AsyncRequesterBootstrap;
+import org.apache.hc.core5.http.impl.bootstrap.HttpAsyncRequester;
+import org.apache.hc.core5.http.nio.AsyncRequestConsumer;
+import org.apache.hc.core5.http.nio.AsyncServerRequestHandler;
+import org.apache.hc.core5.http.nio.entity.AsyncEntityProducers;
+import org.apache.hc.core5.http.nio.entity.DiscardingEntityConsumer;
+import org.apache.hc.core5.http.nio.support.BasicRequestConsumer;
+import org.apache.hc.core5.http.nio.support.BasicRequestProducer;
+import org.apache.hc.core5.http.nio.support.BasicResponseConsumer;
+import org.apache.hc.core5.http.nio.support.BasicResponseProducer;
+import org.apache.hc.core5.http.nio.support.BasicServerExchangeHandler;
+import org.apache.hc.core5.http.protocol.HttpContext;
+import org.apache.hc.core5.io.CloseMode;
+import org.apache.hc.core5.reactor.IOReactorConfig;
+import org.apache.hc.core5.testing.nio.Http1TestServer;
+import org.apache.hc.core5.util.Timeout;
+import org.openjdk.jmh.annotations.Benchmark;
+import org.openjdk.jmh.annotations.BenchmarkMode;
+import org.openjdk.jmh.annotations.Fork;
+import org.openjdk.jmh.annotations.Level;
+import org.openjdk.jmh.annotations.Measurement;
+import org.openjdk.jmh.annotations.Mode;
+import org.openjdk.jmh.annotations.OutputTimeUnit;
+import org.openjdk.jmh.annotations.Param;
+import org.openjdk.jmh.annotations.Scope;
+import org.openjdk.jmh.annotations.Setup;
+import org.openjdk.jmh.annotations.State;
+import org.openjdk.jmh.annotations.TearDown;
+import org.openjdk.jmh.annotations.Threads;
+import org.openjdk.jmh.annotations.Warmup;
+
+/**
+ * End-to-end HTTP/1.1 throughput of a large-body GET over loopback, as a function of the
+ * {@link Http1Config} session buffer size. Both the requester and the server are configured with
+ * the same buffer size, so this isolates the effect of the buffer default on large messages.
+ */
+ at BenchmarkMode(Mode.Throughput)
+ at OutputTimeUnit(TimeUnit.SECONDS)
+ at Warmup(iterations = 3, time = 2, timeUnit = TimeUnit.SECONDS)
+ at Measurement(iterations = 10, time = 2, timeUnit = TimeUnit.SECONDS)
+// A fixed, generous heap keeps GC out of the measurement: at ~6 K x 1 MB/s the transient garbage
+// otherwise triggers frequent collections whose pauses dominate the run-to-run variance.
+ at Fork(value = 1, jvmArgs = {"-Xms4g", "-Xmx4g"})
+// Client and server run in the same JVM, so keep concurrency at or below the available cores to
+// avoid oversubscription noise; override with JMH -t on larger machines.
+ at Threads(8)
+ at State(Scope.Benchmark)
+public class Http1BufferSizeBenchmark {
+
+    @Param({"8192", "16384", "32768", "65536"})
+    public int bufferSize;
+
+    @Param({"1048576"})
+    public int bodySize;
+
+    private static final Timeout TIMEOUT = Timeout.ofSeconds(60);
+
+    private Http1TestServer server;
+    private HttpAsyncRequester requester;
+    private HttpHost target;
+
+    @Setup(Level.Trial)
+    public void setUp() throws Exception {
+        final Http1Config h1Config = Http1Config.custom().setBufferSize(bufferSize).build();
+        final byte[] body = new byte[bodySize];
+
+        server = new Http1TestServer();
+        server.configure(h1Config);
+        server.register("*", () -> new BasicServerExchangeHandler<>(new AsyncServerRequestHandler<Message<HttpRequest, Void>>() {
+
+            @Override
+            public AsyncRequestConsumer<Message<HttpRequest, Void>> prepare(
+                    final HttpRequest request, final EntityDetails entityDetails, final HttpContext context) {
+                return new BasicRequestConsumer<>(entityDetails != null ? new DiscardingEntityConsumer<>() : null);
+            }
+
+            @Override
+            public void handle(
+                    final Message<HttpRequest, Void> message, final ResponseTrigger responseTrigger,
+                    final HttpContext context) throws HttpException, java.io.IOException {
+                responseTrigger.submitResponse(
+                        new BasicResponseProducer(HttpStatus.SC_OK,
+                                AsyncEntityProducers.create(body, ContentType.APPLICATION_OCTET_STREAM)),
+                        context);
+            }
+        }));
+        final InetSocketAddress address = server.start();
+
+        requester = AsyncRequesterBootstrap.bootstrap()
+                .setIOReactorConfig(IOReactorConfig.custom().setSoTimeout(TIMEOUT).build())
+                .setHttp1Config(h1Config)
+                .setMaxTotal(300)
+                .setDefaultMaxPerRoute(300)
+                .create();
+        requester.start();
+        target = new HttpHost("http", "localhost", address.getPort());
+    }
+
+    @TearDown(Level.Trial)
+    public void tearDown() throws Exception {
+        if (requester != null) {
+            requester.close(CloseMode.GRACEFUL);
+        }
+        if (server != null) {
+            server.close();
+        }
+    }
+
+    @Benchmark
+    public long getLargeBody() throws Exception {
+        final Future<Message<HttpResponse, Void>> future = requester.execute(
+                new BasicRequestProducer(Method.GET, target, "/"),
+                new BasicResponseConsumer<>(new DiscardingEntityConsumer<Void>()),
+                TIMEOUT, null);
+        final Message<HttpResponse, Void> message = future.get(TIMEOUT.getDuration(), TIMEOUT.getTimeUnit());
+        return message.getHead().getCode();
+    }
+
+}


=====================================
httpcore5/pom.xml
=====================================
@@ -28,7 +28,7 @@
   <parent>
     <groupId>org.apache.httpcomponents.core5</groupId>
     <artifactId>httpcore5-parent</artifactId>
-    <version>5.4.3</version>
+    <version>5.4.4</version>
   </parent>
   <artifactId>httpcore5</artifactId>
   <name>Apache HttpComponents Core HTTP/1.1</name>


=====================================
httpcore5/src/main/java/org/apache/hc/core5/http/HttpException.java
=====================================
@@ -60,7 +60,7 @@ public class HttpException extends Exception {
             final char ch = chars[i];
             if (ch < FIRST_VALID_CHAR) {
                 builder.append("[0x");
-                final String hexString = Integer.toHexString(i);
+                final String hexString = Integer.toHexString(ch);
                 if (hexString.length() == 1) {
                     builder.append("0");
                 }


=====================================
httpcore5/src/main/java/org/apache/hc/core5/http/config/Http1Config.java
=====================================
@@ -141,7 +141,9 @@ public class Http1Config {
     }
 
     private static final int INIT_WINDOW_SIZE = 65535;
-    private static final int INIT_BUF_SIZE = 8192;
+    // Larger session buffers cut the number of read/write events on large messages; the gain
+    // levels off past 32 KB while per-connection footprint keeps growing, so 32 KB is the default.
+    private static final int INIT_BUF_SIZE = 32 * 1024;
     private static final Timeout INIT_WAIT_FOR_CONTINUE = Timeout.ofSeconds(3);
     private static final int INIT_BUF_CHUNK = -1;
     private static final int INIT_MAX_HEADER_COUNT = 100;


=====================================
httpcore5/src/main/java/org/apache/hc/core5/http/nio/entity/AbstractBinAsyncEntityProducer.java
=====================================
@@ -223,6 +223,7 @@ public abstract class AbstractBinAsyncEntityProducer implements AsyncEntityProdu
     @Override
     public void releaseResources() {
         state = State.ACTIVE;
+        byteBuffer.clear();
     }
 
 }


=====================================
httpcore5/src/main/java/org/apache/hc/core5/http/nio/entity/AbstractCharAsyncEntityProducer.java
=====================================
@@ -245,6 +245,7 @@ public abstract class AbstractCharAsyncEntityProducer implements AsyncEntityProd
     @Override
     public void releaseResources() {
         state = State.ACTIVE;
+        bytebuf.clear();
         charsetEncoder.reset();
     }
 


=====================================
httpcore5/src/main/java/org/apache/hc/core5/http/nio/entity/DigestingEntityProducer.java
=====================================
@@ -155,6 +155,7 @@ public class DigestingEntityProducer implements AsyncEntityProducer {
 
     @Override
     public void releaseResources() {
+        digester.reset();
         wrapped.releaseResources();
     }
 


=====================================
httpcore5/src/main/java/org/apache/hc/core5/http/nio/entity/FileEntityProducer.java
=====================================
@@ -155,6 +155,7 @@ public final class FileEntityProducer implements AsyncEntityProducer {
     @Override
     public void releaseResources() {
         eof = false;
+        byteBuffer.clear();
         Closer.closeQuietly(accessFileRef.getAndSet(null));
     }
 


=====================================
httpcore5/src/main/java/org/apache/hc/core5/http/nio/entity/PathEntityProducer.java
=====================================
@@ -161,6 +161,7 @@ public final class PathEntityProducer implements AsyncEntityProducer {
     @Override
     public void releaseResources() {
         eof = false;
+        byteBuffer.clear();
         Closer.closeQuietly(channelRef.getAndSet(null));
     }
 


=====================================
httpcore5/src/main/java/org/apache/hc/core5/net/URIBuilder.java
=====================================
@@ -207,7 +207,7 @@ public class URIBuilder {
      * Sets the encoding policy for this {@link URIBuilder}.
      * The encoding policy determines how URI components (e.g., query, fragment) are
      * percent-encoded when building the URI string. If not set, the default policy
-     * is {@link EncodingPolicy#RFC_3986}.
+     * is {@link EncodingPolicy#ALL_RESERVED}.
      *
      * @param encodingPolicy the encoding policy to apply, or {@code null} to reset
      *                       to the default ({@link EncodingPolicy#ALL_RESERVED})
@@ -215,7 +215,7 @@ public class URIBuilder {
      * @since 5.4
      */
     public URIBuilder setEncodingPolicy(final EncodingPolicy encodingPolicy) {
-        this.encodingPolicy = encodingPolicy;
+        this.encodingPolicy = encodingPolicy != null ? encodingPolicy : EncodingPolicy.ALL_RESERVED;
         return this;
     }
 


=====================================
httpcore5/src/test/java/org/apache/hc/core5/http/TestHttpExceptions.java
=====================================
@@ -35,7 +35,7 @@ import org.junit.jupiter.api.Test;
  */
 class TestHttpExceptions {
 
-    private static final String CLEAN_MESSAGE = "[0x00]Hello[0x06][0x07][0x08][0x09][0x0a][0x0b][0x0c][0x0d][0x0e][0x0f]World";
+    private static final String CLEAN_MESSAGE = "[0x01]Hello[0x01][0x02][0x03][0x04][0x05][0x06][0x07][0x08][0x09][0x00]World";
     private static final String nonPrintableMessage = String.valueOf(
             new char[] { 1, 'H', 'e', 'l', 'l', 'o', 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 'W', 'o', 'r', 'l', 'd' });
 
@@ -86,4 +86,18 @@ class TestHttpExceptions {
         Assertions.assertEquals(CLEAN_MESSAGE, new UnsupportedHttpVersionException(nonPrintableMessage).getMessage());
     }
 
+
+    @Test
+    void testControlCharacterEscaping() {
+        final HttpException exception = new HttpException("0123456789abcdef\nsuffix");
+
+        Assertions.assertEquals("0123456789abcdef[0x0a]suffix", exception.getMessage());
+    }
+
+    @Test
+    void testControlCharacterEncodingIndependentOfPosition() {
+        Assertions.assertEquals("a[0x0a]b", new HttpException("a\nb").getMessage());
+        Assertions.assertEquals("0123456789abcdef[0x0a]b", new HttpException("0123456789abcdef\nb").getMessage());
+    }
+
 }


=====================================
httpcore5/src/test/java/org/apache/hc/core5/http/nio/entity/TestAbstractBinAsyncEntityProducer.java
=====================================
@@ -82,6 +82,48 @@ class TestAbstractBinAsyncEntityProducer {
 
     }
 
+    static private class RepeatableByteAsyncEntityProducer extends AbstractBinAsyncEntityProducer {
+
+        private final ByteBuffer content;
+
+        public RepeatableByteAsyncEntityProducer(
+                final int fragmentSizeHint,
+                final ContentType contentType,
+                final byte[] content) {
+            super(fragmentSizeHint, contentType);
+            this.content = ByteBuffer.wrap(content);
+        }
+
+        @Override
+        public boolean isRepeatable() {
+            return true;
+        }
+
+        @Override
+        protected int availableData() {
+            return Integer.MAX_VALUE;
+        }
+
+        @Override
+        protected void produceData(final StreamChannel<ByteBuffer> channel) throws IOException {
+            channel.write(content);
+            if (!content.hasRemaining()) {
+                channel.endStream();
+            }
+        }
+
+        @Override
+        public void failed(final Exception cause) {
+        }
+
+        @Override
+        public void releaseResources() {
+            content.clear();
+            super.releaseResources();
+        }
+
+    }
+
     @Test
     void testProduceDataNoBuffering() throws Exception {
 
@@ -184,4 +226,22 @@ class TestAbstractBinAsyncEntityProducer {
 
     }
 
+    @Test
+    void testProduceDataRepeatableAfterPartialWrite() throws Exception {
+        final AsyncEntityProducer producer = new RepeatableByteAsyncEntityProducer(
+                6, ContentType.TEXT_PLAIN, "abcdef".getBytes(StandardCharsets.US_ASCII));
+
+        final WritableByteChannelMock partialByteChannel = new WritableByteChannelMock(1024, 3);
+        producer.produce(new BasicDataStreamChannel(partialByteChannel));
+        Assertions.assertEquals("abc", partialByteChannel.dump(StandardCharsets.US_ASCII));
+        producer.releaseResources();
+
+        final WritableByteChannelMock byteChannel = new WritableByteChannelMock(1024);
+        final DataStreamChannel streamChannel = new BasicDataStreamChannel(byteChannel);
+        producer.produce(streamChannel);
+
+        Assertions.assertFalse(byteChannel.isOpen());
+        Assertions.assertEquals("abcdef", byteChannel.dump(StandardCharsets.US_ASCII));
+    }
+
 }


=====================================
httpcore5/src/test/java/org/apache/hc/core5/http/nio/entity/TestDigestingEntityProducer.java
=====================================
@@ -34,6 +34,7 @@ import org.apache.hc.core5.http.ContentType;
 import org.apache.hc.core5.http.Header;
 import org.apache.hc.core5.http.WritableByteChannelMock;
 import org.apache.hc.core5.http.nio.BasicDataStreamChannel;
+import org.apache.hc.core5.util.TextUtils;
 import org.junit.jupiter.api.Assertions;
 import org.junit.jupiter.api.Test;
 
@@ -62,4 +63,29 @@ class TestDigestingEntityProducer {
         Assertions.assertEquals("827ccb0eea8a706c4c34a16891f84e7b", trailers.get(1).getValue());
     }
 
+    @Test
+    void testProduceDataRepeatableAfterPartialWrite() throws Exception {
+        final DigestingEntityProducer producer = new DigestingEntityProducer("MD5",
+                new StringAsyncEntityProducer("abcdef", 6, 6, ContentType.TEXT_PLAIN));
+
+        final WritableByteChannelMock partialByteChannel = new WritableByteChannelMock(1024, 3);
+        producer.produce(new BasicDataStreamChannel(partialByteChannel));
+        Assertions.assertEquals("abc", partialByteChannel.dump(StandardCharsets.US_ASCII));
+        producer.releaseResources();
+
+        final WritableByteChannelMock byteChannel = new WritableByteChannelMock(1024);
+        final BasicDataStreamChannel dataStreamChannel = new BasicDataStreamChannel(byteChannel);
+        while (byteChannel.isOpen()) {
+            producer.produce(dataStreamChannel);
+        }
+
+        Assertions.assertEquals("abcdef", byteChannel.dump(StandardCharsets.US_ASCII));
+        Assertions.assertEquals("e80b5017098950fc58aad83c8c14978e", TextUtils.toHexString(producer.getDigest()));
+
+        final List<Header> trailers = dataStreamChannel.getTrailers();
+        Assertions.assertNotNull(trailers);
+        Assertions.assertEquals("digest", trailers.get(1).getName());
+        Assertions.assertEquals("e80b5017098950fc58aad83c8c14978e", trailers.get(1).getValue());
+    }
+
 }


=====================================
httpcore5/src/test/java/org/apache/hc/core5/http/nio/entity/TestFileAsyncEntityProducer.java
=====================================
@@ -104,4 +104,22 @@ class TestFileAsyncEntityProducer {
         }
     }
 
+    @Test
+    void testTextContentRepeatableAfterPartialWrite() throws Exception {
+        final AsyncEntityProducer producer = new FileEntityProducer(tempFile, ContentType.TEXT_PLAIN);
+
+        final WritableByteChannelMock partialByteChannel = new WritableByteChannelMock(1024, 3);
+        producer.produce(new BasicDataStreamChannel(partialByteChannel));
+        Assertions.assertEquals("abc", partialByteChannel.dump(StandardCharsets.US_ASCII));
+        producer.releaseResources();
+
+        final WritableByteChannelMock byteChannel = new WritableByteChannelMock(1024);
+        final DataStreamChannel streamChannel = new BasicDataStreamChannel(byteChannel);
+        producer.produce(streamChannel);
+        producer.produce(streamChannel);
+
+        Assertions.assertFalse(byteChannel.isOpen());
+        Assertions.assertEquals("abcdef", byteChannel.dump(StandardCharsets.US_ASCII));
+    }
+
 }


=====================================
httpcore5/src/test/java/org/apache/hc/core5/http/nio/entity/TestPathAsyncEntityProducer.java
=====================================
@@ -109,4 +109,23 @@ class TestPathAsyncEntityProducer {
         }
     }
 
+    @Test
+    void testTextContentRepeatableAfterPartialWrite() throws Exception {
+        final Path tempPath = tempFile.toPath();
+        final AsyncEntityProducer producer = new PathEntityProducer(tempPath, ContentType.TEXT_PLAIN, StandardOpenOption.READ);
+
+        final WritableByteChannelMock partialByteChannel = new WritableByteChannelMock(1024, 3);
+        producer.produce(new BasicDataStreamChannel(partialByteChannel));
+        Assertions.assertEquals("abc", partialByteChannel.dump(StandardCharsets.US_ASCII));
+        producer.releaseResources();
+
+        final WritableByteChannelMock byteChannel = new WritableByteChannelMock(1024);
+        final DataStreamChannel streamChannel = new BasicDataStreamChannel(byteChannel);
+        producer.produce(streamChannel);
+        producer.produce(streamChannel);
+
+        Assertions.assertFalse(byteChannel.isOpen());
+        Assertions.assertEquals("abcdef", byteChannel.dump(StandardCharsets.US_ASCII));
+    }
+
 }


=====================================
httpcore5/src/test/java/org/apache/hc/core5/http/nio/entity/TestStringAsyncEntityProducer.java
=====================================
@@ -80,4 +80,23 @@ class TestStringAsyncEntityProducer {
         }
     }
 
+    @Test
+    void testTextContentRepeatableAfterPartialWrite() throws Exception {
+        final AsyncEntityProducer producer = new StringAsyncEntityProducer(
+                "abcdef", 6, 6, ContentType.TEXT_PLAIN);
+
+        final WritableByteChannelMock partialByteChannel = new WritableByteChannelMock(1024, 3);
+        producer.produce(new BasicDataStreamChannel(partialByteChannel));
+        Assertions.assertEquals("abc", partialByteChannel.dump(StandardCharsets.US_ASCII));
+        producer.releaseResources();
+
+        final WritableByteChannelMock byteChannel = new WritableByteChannelMock(1024);
+        final DataStreamChannel streamChannel = new BasicDataStreamChannel(byteChannel);
+        producer.produce(streamChannel);
+        producer.produce(streamChannel);
+
+        Assertions.assertFalse(byteChannel.isOpen());
+        Assertions.assertEquals("abcdef", byteChannel.dump(StandardCharsets.US_ASCII));
+    }
+
 }


=====================================
httpcore5/src/test/java/org/apache/hc/core5/net/TestURIBuilder.java
=====================================
@@ -998,6 +998,39 @@ class TestURIBuilder {
         Assertions.assertEquals("hello world", params.get(0).getValue());
     }
 
+    @Test
+    void testDefaultEncodingPolicy() throws Exception {
+        final URIBuilder builder = new URIBuilder()
+                .setScheme("http")
+                .setHost("example.com")
+                .setPath("/a:b")
+                .addParameter("key", "a/b")
+                .setFragment("a/b");
+        final URI expected = new URI("http://example.com/a%3Ab?key=a%2Fb#a%2Fb");
+
+        Assertions.assertEquals(expected, builder.build());
+        builder.setEncodingPolicy(URIBuilder.EncodingPolicy.ALL_RESERVED);
+        Assertions.assertEquals(expected, builder.build());
+        builder.setEncodingPolicy(null);
+        Assertions.assertEquals(expected, builder.build());
+    }
+
+    @Test
+    void testResetEncodingPolicy() throws Exception {
+        final URIBuilder builder = new URIBuilder()
+                .setScheme("http")
+                .setUserInfo("user!")
+                .setHost("example.com")
+                .setPath("/a:b")
+                .setCustomQuery("a/b")
+                .setFragment("a/b")
+                .setEncodingPolicy(URIBuilder.EncodingPolicy.RFC_3986);
+
+        Assertions.assertEquals(new URI("http://user!@example.com/a:b?a/b#a/b"), builder.build());
+        Assertions.assertSame(builder, builder.setEncodingPolicy(null));
+        Assertions.assertEquals(new URI("http://user%21@example.com/a%3Ab?a%2Fb#a%2Fb"), builder.build());
+    }
+
     @Test
     void testCustomQueryEncoding() throws Exception {
         final String query = "query param:!@/?\"";


=====================================
pom.xml
=====================================
@@ -33,7 +33,7 @@
   <groupId>org.apache.httpcomponents.core5</groupId>
   <artifactId>httpcore5-parent</artifactId>
   <name>Apache HttpComponents Core</name>
-  <version>5.4.3</version>
+  <version>5.4.4</version>
   <description>Apache HttpComponents Core is a library of components for building HTTP enabled services</description>
   <url>https://hc.apache.org/httpcomponents-core-5.4.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.4.3</tag>
+    <tag>5.4.4</tag>
   </scm>
 
   <distributionManagement>



View it on GitLab: https://salsa.debian.org/java-team/httpcomponents-core5/-/commit/d3056127325e0ff0d7835c722e2ff84dc395ffc9

-- 
View it on GitLab: https://salsa.debian.org/java-team/httpcomponents-core5/-/commit/d3056127325e0ff0d7835c722e2ff84dc395ffc9
You're receiving this email because of your account on salsa.debian.org. Manage all notifications: https://salsa.debian.org/-/profile/notifications | Help: https://salsa.debian.org/help


-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://alioth-lists.debian.net/pipermail/pkg-java-commits/attachments/20260925/c8b53e2e/attachment.htm>


More information about the pkg-java-commits mailing list