[Git][java-team/httpcomponents-core5][master] 4 commits: New upstream version 5.2.2
Markus Koschany (@apo)
gitlab at salsa.debian.org
Mon Sep 11 12:33:43 BST 2023
Markus Koschany pushed to branch master at Debian Java Maintainers / httpcomponents-core5
Commits:
0046c587 by Markus Koschany at 2023-09-11T13:18:58+02:00
New upstream version 5.2.2
- - - - -
30bc06f6 by Markus Koschany at 2023-09-11T13:19:00+02:00
Update upstream source from tag 'upstream/5.2.2'
Update to upstream version '5.2.2'
with Debian dir e03089a5d24e6d99a74978a34e3122a4c0a4461a
- - - - -
31f69eb6 by Markus Koschany at 2023-09-11T13:20:19+02:00
Mark libhttpcore5-java Multi-Arch: foreign.
- - - - -
315e39d9 by Markus Koschany at 2023-09-11T13:23:05+02:00
Update changelog
- - - - -
28 changed files:
- RELEASE_NOTES.txt
- debian/changelog
- debian/control
- httpcore5-h2/pom.xml
- httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/nio/AbstractH2StreamMultiplexer.java
- httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/nio/FrameOutputBuffer.java
- httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/nio/bootstrap/H2MultiplexingRequester.java
- httpcore5-h2/src/test/java/org/apache/hc/core5/http2/impl/nio/TestFrameInOutBuffers.java
- httpcore5-reactive/pom.xml
- httpcore5-testing/pom.xml
- httpcore5-testing/src/main/java/org/apache/hc/core5/testing/nio/LoggingIOSessionListener.java
- + httpcore5-testing/src/test/java/org/apache/hc/core5/testing/nio/H2ConnPoolTest.java
- httpcore5/pom.xml
- httpcore5/src/main/java/org/apache/hc/core5/http/ContentType.java
- httpcore5/src/main/java/org/apache/hc/core5/http/message/AbstractMessageWrapper.java
- httpcore5/src/main/java/org/apache/hc/core5/http/message/BasicHttpRequest.java
- httpcore5/src/main/java/org/apache/hc/core5/http/message/HttpRequestWrapper.java
- httpcore5/src/main/java/org/apache/hc/core5/http/message/HttpResponseWrapper.java
- httpcore5/src/main/java/org/apache/hc/core5/http/nio/entity/BasicAsyncEntityProducer.java
- httpcore5/src/main/java/org/apache/hc/core5/reactor/AbstractIOSessionPool.java
- httpcore5/src/main/java/org/apache/hc/core5/reactor/SingleCoreIOReactor.java
- httpcore5/src/main/java/org/apache/hc/core5/reactor/ssl/SSLIOSession.java
- httpcore5/src/test/java/org/apache/hc/core5/http/TestContentType.java
- httpcore5/src/test/java/org/apache/hc/core5/http/examples/ClassicPostExecutionExample.java
- httpcore5/src/test/java/org/apache/hc/core5/http/message/TestBasicMessages.java
- httpcore5/src/test/java/org/apache/hc/core5/http/nio/entity/TestBasicAsyncEntityProducer.java
- + httpcore5/src/test/java/org/apache/hc/core5/reactor/ssl/SSLIOSessionTest.java
- pom.xml
Changes:
=====================================
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
------------------
=====================================
debian/changelog
=====================================
@@ -1,3 +1,10 @@
+httpcomponents-core5 (5.2.2-1) unstable; urgency=medium
+
+ * New upstream version 5.2.2.
+ * Mark libhttpcore5-java Multi-Arch: foreign.
+
+ -- Markus Koschany <apo at debian.org> Mon, 11 Sep 2023 13:20:59 +0200
+
httpcomponents-core5 (5.2.1-1) unstable; urgency=medium
* New upstream version 5.2.1.
=====================================
debian/control
=====================================
@@ -19,6 +19,7 @@ Vcs-Browser: https://salsa.debian.org/java-team/httpcomponents-core5
Homepage: https://hc.apache.org/
Package: libhttpcore5-java
+Multi-Arch: foreign
Architecture: all
Depends:
${maven:Depends},
=====================================
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>
=====================================
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) {
=====================================
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) {
=====================================
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;
+ }
+
}
=====================================
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());
+ }
+
}
=====================================
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>
=====================================
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>
=====================================
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
=====================================
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());
+ }
+
+}
=====================================
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>
=====================================
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
*/
=====================================
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();
=====================================
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) {
=====================================
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);
}
}
=====================================
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);
}
}
=====================================
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);
}
}
=====================================
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;
=====================================
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);
}
=====================================
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);
}
=====================================
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",
=====================================
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();
=====================================
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());
+ }
+
}
=====================================
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();
+ }
+ }
+
}
=====================================
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);
+ }
+ }
+
+}
+
+
=====================================
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>
View it on GitLab: https://salsa.debian.org/java-team/httpcomponents-core5/-/compare/16af7d69a98c36dabdb499fde10de3f59ff87679...315e39d9dfff7849e5a7ea764e61aad5c1e0e13f
--
View it on GitLab: https://salsa.debian.org/java-team/httpcomponents-core5/-/compare/16af7d69a98c36dabdb499fde10de3f59ff87679...315e39d9dfff7849e5a7ea764e61aad5c1e0e13f
You're receiving this email because of your account on salsa.debian.org.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://alioth-lists.debian.net/pipermail/pkg-java-commits/attachments/20230911/c09474db/attachment.htm>
More information about the pkg-java-commits
mailing list