@@ -69,52 +69,52 @@
io.netty
netty-buffer
- 4.1.137.Final
+ 4.2.17.Final
io.netty
- netty-codec
- 4.1.137.Final
+ netty-codec-base
+ 4.2.17.Final
io.netty
netty-codec-http
- 4.1.137.Final
+ 4.2.17.Final
io.netty
netty-codec-http2
- 4.1.137.Final
+ 4.2.17.Final
io.netty
netty-common
- 4.1.137.Final
+ 4.2.17.Final
io.netty
netty-handler
- 4.1.137.Final
+ 4.2.17.Final
io.netty
netty-handler-proxy
- 4.1.137.Final
+ 4.2.17.Final
io.netty
netty-resolver
- 4.1.137.Final
+ 4.2.17.Final
io.netty
netty-resolver-dns
- 4.1.137.Final
+ 4.2.17.Final
io.netty
netty-transport
- 4.1.137.Final
+ 4.2.17.Final
@@ -126,32 +126,18 @@
test
-
- io.netty
- netty-transport-native-unix-common
- 4.1.137.Final
- linux-x86_64
- test
-
io.netty
netty-transport-native-epoll
- 4.1.137.Final
+ 4.2.17.Final
linux-x86_64
test
-
- io.netty
- netty-transport-native-unix-common
- 4.1.137.Final
- osx-x86_64
- test
-
io.netty
netty-transport-native-kqueue
- 4.1.137.Final
+ 4.2.17.Final
osx-x86_64
test
@@ -223,16 +209,16 @@
- io.netty:netty-buffer:[4.1.137.Final]
- io.netty:netty-codec:[4.1.137.Final]
- io.netty:netty-codec-http:[4.1.137.Final]
- io.netty:netty-codec-http2:[4.1.137.Final]
- io.netty:netty-common:[4.1.137.Final]
- io.netty:netty-handler:[4.1.137.Final]
- io.netty:netty-handler-proxy:[4.1.137.Final]
- io.netty:netty-resolver:[4.1.137.Final]
- io.netty:netty-resolver-dns:[4.1.137.Final]
- io.netty:netty-transport:[4.1.137.Final]
+ io.netty:netty-buffer:[4.2.17.Final]
+ io.netty:netty-codec-base:[4.2.17.Final]
+ io.netty:netty-codec-http:[4.2.17.Final]
+ io.netty:netty-codec-http2:[4.2.17.Final]
+ io.netty:netty-common:[4.2.17.Final]
+ io.netty:netty-handler:[4.2.17.Final]
+ io.netty:netty-handler-proxy:[4.2.17.Final]
+ io.netty:netty-resolver:[4.2.17.Final]
+ io.netty:netty-resolver-dns:[4.2.17.Final]
+ io.netty:netty-transport:[4.2.17.Final]
diff --git a/sdk/clientcore/http-netty4/src/main/java/io/clientcore/http/netty4/NettyHttpClientBuilder.java b/sdk/clientcore/http-netty4/src/main/java/io/clientcore/http/netty4/NettyHttpClientBuilder.java
index 68c163abd001..dde7adde03c7 100644
--- a/sdk/clientcore/http-netty4/src/main/java/io/clientcore/http/netty4/NettyHttpClientBuilder.java
+++ b/sdk/clientcore/http-netty4/src/main/java/io/clientcore/http/netty4/NettyHttpClientBuilder.java
@@ -12,15 +12,22 @@
import io.clientcore.http.netty4.implementation.ChannelInitializationProxyHandler;
import io.clientcore.http.netty4.implementation.Netty4ConnectionPool;
import io.netty.bootstrap.Bootstrap;
+import io.netty.buffer.ByteBufAllocator;
+import io.netty.buffer.PooledByteBufAllocator;
import io.netty.channel.Channel;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
-import io.netty.channel.nio.NioEventLoopGroup;
+import io.netty.channel.IoEventLoopGroup;
+import io.netty.channel.IoHandler;
+import io.netty.channel.IoHandlerFactory;
+import io.netty.channel.MultiThreadIoEventLoopGroup;
+import io.netty.channel.nio.NioIoHandler;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.ssl.SslContext;
import io.netty.handler.ssl.SslContextBuilder;
import io.netty.util.concurrent.DefaultThreadFactory;
+import io.netty.util.internal.SystemPropertyUtil;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
@@ -36,35 +43,35 @@ public class NettyHttpClientBuilder {
private static final String EPOLL = "io.netty.channel.epoll.Epoll";
private static final String EPOLL_CHANNEL = "io.netty.channel.epoll.EpollSocketChannel";
- private static final String EPOLL_EVENT_LOOP_GROUP = "io.netty.channel.epoll.EpollEventLoopGroup";
+ private static final String EPOLL_IO_HANDLER = "io.netty.channel.epoll.EpollIoHandler";
private static final boolean IS_EPOLL_AVAILABLE;
private static final Class extends SocketChannel> EPOLL_CHANNEL_CLASS;
- private static final Class> EPOLL_EVENT_LOOP_GROUP_CLASS;
- private static final MethodHandle EPOLL_EVENT_LOOP_GROUP_CREATOR;
+ private static final Class extends IoHandler> EPOLL_IO_HANDLER_CLASS;
+ private static final MethodHandle EPOLL_IO_HANDLER_FACTORY_CREATOR;
private static final String KQUEUE = "io.netty.channel.kqueue.KQueue";
private static final String KQUEUE_CHANNEL = "io.netty.channel.kqueue.KQueueSocketChannel";
- private static final String KQUEUE_EVENT_LOOP_GROUP = "io.netty.channel.kqueue.KQueueEventLoopGroup";
+ private static final String KQUEUE_IO_HANDLER = "io.netty.channel.kqueue.KQueueIoHandler";
private static final boolean IS_KQUEUE_AVAILABLE;
private static final Class extends SocketChannel> KQUEUE_CHANNEL_CLASS;
- private static final Class> KQUEUE_EVENT_LOOP_GROUP_CLASS;
- private static final MethodHandle KQUEUE_EVENT_LOOP_GROUP_CREATOR;
+ private static final Class extends IoHandler> KQUEUE_IO_HANDLER_CLASS;
+ private static final MethodHandle KQUEUE_IO_HANDLER_FACTORY_CREATOR;
static {
// Inspect the class path to determine is native transports are available.
// If they are, this will determine runtime behaviors.
boolean isEpollAvailable;
Class extends SocketChannel> epollChannelClass;
- Class> epollEventLoopGroupClass;
- MethodHandle epollEventLoopGroupCreator;
+ Class extends IoHandler> epollIoHandlerClass;
+ MethodHandle epollIoHandlerFactoryCreator;
try {
Class> epollClass = Class.forName(EPOLL);
isEpollAvailable = (boolean) epollClass.getDeclaredMethod("isAvailable").invoke(null);
epollChannelClass = getChannelClass(EPOLL_CHANNEL);
- epollEventLoopGroupClass = Class.forName(EPOLL_EVENT_LOOP_GROUP);
- epollEventLoopGroupCreator = MethodHandles.publicLookup()
- .unreflectConstructor(epollEventLoopGroupClass.getDeclaredConstructor(ThreadFactory.class));
+ epollIoHandlerClass = Class.forName(EPOLL_IO_HANDLER).asSubclass(IoHandler.class);
+ epollIoHandlerFactoryCreator
+ = MethodHandles.publicLookup().unreflect(epollIoHandlerClass.getDeclaredMethod("newFactory"));
LOGGER.atVerbose()
.addKeyValue("epollAvailable", isEpollAvailable)
.log("Lookup for Epoll completed without error.");
@@ -77,27 +84,27 @@ public class NettyHttpClientBuilder {
LOGGER.atVerbose().log("Epoll is unavailable and won't be used.");
isEpollAvailable = false;
epollChannelClass = null;
- epollEventLoopGroupClass = null;
- epollEventLoopGroupCreator = null;
+ epollIoHandlerClass = null;
+ epollIoHandlerFactoryCreator = null;
}
IS_EPOLL_AVAILABLE = isEpollAvailable;
EPOLL_CHANNEL_CLASS = epollChannelClass;
- EPOLL_EVENT_LOOP_GROUP_CLASS = epollEventLoopGroupClass;
- EPOLL_EVENT_LOOP_GROUP_CREATOR = epollEventLoopGroupCreator;
+ EPOLL_IO_HANDLER_CLASS = epollIoHandlerClass;
+ EPOLL_IO_HANDLER_FACTORY_CREATOR = epollIoHandlerFactoryCreator;
boolean isKqueueAvailable;
Class extends SocketChannel> kqueueChannelClass;
- Class> kqueueEventLoopGroupClass;
- MethodHandle kqueueEventLoopGroupCreator;
+ Class extends IoHandler> kqueueIoHandlerClass;
+ MethodHandle kqueueIoHandlerFactoryCreator;
try {
Class> kqueueClass = Class.forName(KQUEUE);
isKqueueAvailable = (boolean) kqueueClass.getDeclaredMethod("isAvailable").invoke(null);
kqueueChannelClass = getChannelClass(KQUEUE_CHANNEL);
- kqueueEventLoopGroupClass = Class.forName(KQUEUE_EVENT_LOOP_GROUP);
- kqueueEventLoopGroupCreator = MethodHandles.publicLookup()
- .unreflectConstructor(kqueueEventLoopGroupClass.getDeclaredConstructor(ThreadFactory.class));
+ kqueueIoHandlerClass = Class.forName(KQUEUE_IO_HANDLER).asSubclass(IoHandler.class);
+ kqueueIoHandlerFactoryCreator
+ = MethodHandles.publicLookup().unreflect(kqueueIoHandlerClass.getDeclaredMethod("newFactory"));
LOGGER.atVerbose()
.addKeyValue("kqueueAvailable", isKqueueAvailable)
.log("Lookup for KQueue completed without error.");
@@ -110,14 +117,14 @@ public class NettyHttpClientBuilder {
LOGGER.atVerbose().log("KQueue is unavailable and won't be used.");
isKqueueAvailable = false;
kqueueChannelClass = null;
- kqueueEventLoopGroupClass = null;
- kqueueEventLoopGroupCreator = null;
+ kqueueIoHandlerClass = null;
+ kqueueIoHandlerFactoryCreator = null;
}
IS_KQUEUE_AVAILABLE = isKqueueAvailable;
KQUEUE_CHANNEL_CLASS = kqueueChannelClass;
- KQUEUE_EVENT_LOOP_GROUP_CLASS = kqueueEventLoopGroupClass;
- KQUEUE_EVENT_LOOP_GROUP_CREATOR = kqueueEventLoopGroupCreator;
+ KQUEUE_IO_HANDLER_CLASS = kqueueIoHandlerClass;
+ KQUEUE_IO_HANDLER_FACTORY_CREATOR = kqueueIoHandlerFactoryCreator;
}
@SuppressWarnings("unchecked")
@@ -154,10 +161,10 @@ public NettyHttpClientBuilder() {
* Sets the event loop group for the Netty client.
*
* By default, if no {@code eventLoopGroup} is configured and no native transports are available (Epoll KQueue)
- * {@link NioEventLoopGroup} will be used.
+ * a {@link MultiThreadIoEventLoopGroup} using {@link NioIoHandler} will be used.
*
- * If native transports are available, the {@link EventLoopGroup} implementation for the native transport will be
- * chosen over {@link NioEventLoopGroup}.
+ * If native transports are available, the {@link IoHandlerFactory} for the native transport will be
+ * chosen over {@link NioIoHandler}.
*
* @param eventLoopGroup The event loop group.
* @return The updated builder.
@@ -377,9 +384,9 @@ public NettyHttpClientBuilder maxPendingAcquires(int maxPendingAcquires) {
*/
public HttpClient build() {
EventLoopGroup group = getEventLoopGroupToUse(this.eventLoopGroup, this.channelClass, IS_EPOLL_AVAILABLE,
- EPOLL_EVENT_LOOP_GROUP_CREATOR, IS_KQUEUE_AVAILABLE, KQUEUE_EVENT_LOOP_GROUP_CREATOR);
+ EPOLL_IO_HANDLER_FACTORY_CREATOR, IS_KQUEUE_AVAILABLE, KQUEUE_IO_HANDLER_FACTORY_CREATOR);
Class extends Channel> channelClass
- = getChannelClass(this.channelClass, group.getClass(), IS_EPOLL_AVAILABLE, IS_KQUEUE_AVAILABLE);
+ = getChannelClass(this.channelClass, group, IS_EPOLL_AVAILABLE, IS_KQUEUE_AVAILABLE);
// Leave breadcrumbs about the NettyHttpClient configuration, in case troubleshooting is needed.
LoggingEvent loggingEvent = LOGGER.atVerbose()
@@ -401,6 +408,11 @@ public HttpClient build() {
Bootstrap bootstrap = new Bootstrap().group(group)
.channel(channelClass)
.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, (int) getTimeoutMillis(connectTimeout, 10_000));
+ // Preserve the pooled default from Netty 4.1 while honoring an explicitly configured Netty allocator.
+ bootstrap.option(ChannelOption.ALLOCATOR,
+ SystemPropertyUtil.contains("io.netty.allocator.type")
+ ? ByteBufAllocator.DEFAULT
+ : PooledByteBufAllocator.DEFAULT);
// Disable auto-read as we want to control when and how data is read from the channel.
bootstrap.option(ChannelOption.AUTO_READ, false);
// Enable TCP keep-alive to proactively detect and clean up stale connections in the pool. This helps evict
@@ -455,47 +467,52 @@ ProxyOptions getProxyOptions() {
static EventLoopGroup getEventLoopGroupToUse(EventLoopGroup configuredGroup,
Class extends SocketChannel> configuredChannelClass, boolean isEpollAvailable,
- MethodHandle epollEventLoopGroupCreator, boolean isKqueueAvailable, MethodHandle kqueueEventLoopGroupCreator) {
+ MethodHandle epollIoHandlerFactoryCreator, boolean isKqueueAvailable,
+ MethodHandle kqueueIoHandlerFactoryCreator) {
if (configuredGroup != null) {
return configuredGroup;
}
ThreadFactory threadFactory = new DefaultThreadFactory("clientcore-netty-client", true);
- // Use EpollEventLoopGroup if Epoll is available and 'channelClass' wasn't configured or was configured to
+ // Use Epoll if available and 'channelClass' wasn't configured or was configured to
// EpollSocketChannel.
if (isEpollAvailable && (configuredChannelClass == null || configuredChannelClass == EPOLL_CHANNEL_CLASS)) {
try {
- return (EventLoopGroup) epollEventLoopGroupCreator.invoke(threadFactory);
+ return new MultiThreadIoEventLoopGroup(threadFactory,
+ (IoHandlerFactory) epollIoHandlerFactoryCreator.invoke());
} catch (Throwable ex) {
- LOGGER.atVerbose().setThrowable(ex).log("Failed to create an EpollEventLoopGroup.");
+ LOGGER.atVerbose().setThrowable(ex).log("Failed to create an Epoll event loop group.");
}
}
- // Use KQueueEventLoopGroup if KQueue is available and 'channelClass' wasn't configured or was configured to
+ // Use KQueue if available and 'channelClass' wasn't configured or was configured to
// KQueueSocketChannel.
if (isKqueueAvailable && (configuredChannelClass == null || configuredChannelClass == KQUEUE_CHANNEL_CLASS)) {
try {
- return (EventLoopGroup) kqueueEventLoopGroupCreator.invoke(threadFactory);
+ return new MultiThreadIoEventLoopGroup(threadFactory,
+ (IoHandlerFactory) kqueueIoHandlerFactoryCreator.invoke());
} catch (Throwable ex) {
- LOGGER.atVerbose().setThrowable(ex).log("Failed to create a KQueueEventLoopGroup.");
+ LOGGER.atVerbose().setThrowable(ex).log("Failed to create a KQueue event loop group.");
}
}
- // Fallback to NioEventLoopGroup.
- return new NioEventLoopGroup(threadFactory);
+ // Fall back to NIO.
+ return new MultiThreadIoEventLoopGroup(threadFactory, NioIoHandler.newFactory());
}
static Class extends SocketChannel> getChannelClass(Class extends SocketChannel> configuredChannelClass,
- Class extends EventLoopGroup> configuredGroupClass, boolean isEpollAvailable, boolean isKqueueAvailable) {
+ EventLoopGroup configuredGroup, boolean isEpollAvailable, boolean isKqueueAvailable) {
if (configuredChannelClass != null) {
// If the Channel class was manually set, use it.
return configuredChannelClass;
- } else if (isEpollAvailable && configuredGroupClass == EPOLL_EVENT_LOOP_GROUP_CLASS) {
- // If Epoll is available and the EventLoopGroup is EpollEventLoopGroup, use EpollSocketChannel.
+ } else if (isEpollAvailable
+ && configuredGroup instanceof IoEventLoopGroup
+ && ((IoEventLoopGroup) configuredGroup).isIoType(EPOLL_IO_HANDLER_CLASS)) {
return EPOLL_CHANNEL_CLASS;
- } else if (isKqueueAvailable && configuredGroupClass == KQUEUE_EVENT_LOOP_GROUP_CLASS) {
- // If KQueue is available and the EventLoopGroup is KQueueEventLoopGroup, use KQueueSocketChannel.
+ } else if (isKqueueAvailable
+ && configuredGroup instanceof IoEventLoopGroup
+ && ((IoEventLoopGroup) configuredGroup).isIoType(KQUEUE_IO_HANDLER_CLASS)) {
return KQUEUE_CHANNEL_CLASS;
} else {
// Fallback to NioSocketChannel.
diff --git a/sdk/clientcore/http-netty4/src/main/java/io/clientcore/http/netty4/implementation/Netty4Utility.java b/sdk/clientcore/http-netty4/src/main/java/io/clientcore/http/netty4/implementation/Netty4Utility.java
index f0d7835c190f..4bdffdc966f8 100644
--- a/sdk/clientcore/http-netty4/src/main/java/io/clientcore/http/netty4/implementation/Netty4Utility.java
+++ b/sdk/clientcore/http-netty4/src/main/java/io/clientcore/http/netty4/implementation/Netty4Utility.java
@@ -85,10 +85,12 @@ public final class Netty4Utility {
// Non-native dependencies are required while native dependencies are optional. Without the native dependencies
// the SDK will fall back to using the JDK implementations.
private static final List REQUIRED_NETTY_VERSION_ARTIFACTS
- = Arrays.asList("netty-buffer", "netty-codec", "netty-codec-http", "netty-codec-http2", "netty-common",
- "netty-handler", "netty-handler-proxy", "netty-resolver", "netty-resolver-dns", "netty-transport");
- private static final List OPTIONAL_NETTY_VERSION_ARTIFACTS = Arrays
- .asList("netty-transport-native-unix-common", "netty-transport-native-epoll", "netty-transport-native-kqueue");
+ = Arrays.asList("netty-buffer", "netty-codec-base", "netty-codec-compression", "netty-codec-dns",
+ "netty-codec-socks", "netty-codec-http", "netty-codec-http2", "netty-common", "netty-handler",
+ "netty-handler-proxy", "netty-resolver", "netty-resolver-dns", "netty-transport");
+ private static final List OPTIONAL_NETTY_VERSION_ARTIFACTS
+ = Arrays.asList("netty-transport-native-unix-common", "netty-transport-native-epoll",
+ "netty-transport-native-kqueue", "netty-transport-classes-epoll", "netty-transport-classes-kqueue");
private static final int TWO_FIFTY_SIX_KB = 256 * 1024;
diff --git a/sdk/clientcore/http-netty4/src/main/java/module-info.java b/sdk/clientcore/http-netty4/src/main/java/module-info.java
index 2ab0fc5e7223..a9e31d53266b 100644
--- a/sdk/clientcore/http-netty4/src/main/java/module-info.java
+++ b/sdk/clientcore/http-netty4/src/main/java/module-info.java
@@ -14,6 +14,7 @@
requires io.netty.common;
requires io.netty.handler.proxy;
requires io.netty.codec;
+ requires io.netty.codec.compression;
requires io.netty.resolver;
requires io.netty.codec.http2;
requires java.sql;
diff --git a/sdk/clientcore/http-netty4/src/test/java/io/clientcore/http/netty4/NettyHttp2HttpClientTests.java b/sdk/clientcore/http-netty4/src/test/java/io/clientcore/http/netty4/NettyHttp2HttpClientTests.java
index dba6aa10bbea..7a454a7650fe 100644
--- a/sdk/clientcore/http-netty4/src/test/java/io/clientcore/http/netty4/NettyHttp2HttpClientTests.java
+++ b/sdk/clientcore/http-netty4/src/test/java/io/clientcore/http/netty4/NettyHttp2HttpClientTests.java
@@ -17,12 +17,21 @@
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.Timeout;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.ValueSource;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.nio.charset.StandardCharsets;
import java.security.SecureRandom;
import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.TimeUnit;
+import java.util.zip.DeflaterOutputStream;
+import java.util.zip.GZIPOutputStream;
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
+import static org.junit.jupiter.api.Assertions.assertEquals;
@Timeout(value = 3, unit = TimeUnit.MINUTES)
public class NettyHttp2HttpClientTests extends HttpClientTests {
@@ -93,4 +102,31 @@ public void canSendBinaryDataDebug() {
assertArrayEquals(expectedBytes, response.getValue().toBytes());
}
}
+
+ @ParameterizedTest
+ @ValueSource(strings = { "gzip", "deflate" })
+ public void decompressesResponse(String contentEncoding) throws IOException {
+ byte[] expected = "Compressed HTTP/2 response".getBytes(StandardCharsets.UTF_8);
+ ByteArrayOutputStream compressed = new ByteArrayOutputStream();
+ try (OutputStream compressor = "gzip".equals(contentEncoding)
+ ? new GZIPOutputStream(compressed)
+ : new DeflaterOutputStream(compressed)) {
+ compressor.write(expected);
+ }
+ byte[] compressedBytes = compressed.toByteArray();
+ LocalTestServer compressedServer
+ = new LocalTestServer(HttpProtocolVersion.HTTP_2, true, (request, response, requestBody) -> {
+ response.setHeader("Content-Encoding", contentEncoding);
+ response.setContentLength(compressedBytes.length);
+ response.getOutputStream().write(compressedBytes);
+ });
+ compressedServer.start();
+ try (Response response = getHttpClient()
+ .send(new HttpRequest().setMethod(HttpMethod.GET).setUri(compressedServer.getHttpsUri()))) {
+ assertEquals(200, response.getStatusCode());
+ assertArrayEquals(expected, response.getValue().toBytes());
+ } finally {
+ compressedServer.stop();
+ }
+ }
}
diff --git a/sdk/clientcore/http-netty4/src/test/java/io/clientcore/http/netty4/NettyHttpClientBuilderTests.java b/sdk/clientcore/http-netty4/src/test/java/io/clientcore/http/netty4/NettyHttpClientBuilderTests.java
index a417ef32f253..3263eeec0f78 100644
--- a/sdk/clientcore/http-netty4/src/test/java/io/clientcore/http/netty4/NettyHttpClientBuilderTests.java
+++ b/sdk/clientcore/http-netty4/src/test/java/io/clientcore/http/netty4/NettyHttpClientBuilderTests.java
@@ -13,15 +13,23 @@
import io.clientcore.core.utils.configuration.Configuration;
import io.clientcore.http.netty4.implementation.NettyHttpClientLocalTestServer;
import io.netty.bootstrap.BootstrapConfig;
+import io.netty.buffer.ByteBufAllocator;
+import io.netty.buffer.PooledByteBufAllocator;
import io.netty.channel.Channel;
+import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
-import io.netty.channel.epoll.EpollEventLoopGroup;
+import io.netty.channel.IoEventLoopGroup;
+import io.netty.channel.IoHandler;
+import io.netty.channel.IoHandlerFactory;
+import io.netty.channel.MultiThreadIoEventLoopGroup;
+import io.netty.channel.epoll.EpollIoHandler;
import io.netty.channel.epoll.EpollSocketChannel;
-import io.netty.channel.kqueue.KQueueEventLoopGroup;
+import io.netty.channel.kqueue.KQueueIoHandler;
import io.netty.channel.kqueue.KQueueSocketChannel;
-import io.netty.channel.nio.NioEventLoopGroup;
+import io.netty.channel.nio.NioIoHandler;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
+import io.netty.resolver.DefaultAddressResolverGroup;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.Timeout;
import org.junit.jupiter.api.condition.EnabledOnOs;
@@ -38,7 +46,6 @@
import java.time.Duration;
import java.util.ArrayList;
import java.util.List;
-import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;
import java.util.function.Supplier;
import java.util.stream.Stream;
@@ -50,6 +57,13 @@
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertSame;
import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.atLeastOnce;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoInteractions;
+import static org.mockito.Mockito.when;
/**
* Tests {@link NettyHttpClientBuilder}.
@@ -286,12 +300,16 @@ private static Stream buildWithExplicitConfigurationProxySupplier
@Test
public void buildEventLoopClient() {
String expectedThreadName = "testEventLoop";
- NioEventLoopGroup eventLoopGroup = new NioEventLoopGroup(1, (Runnable r) -> new Thread(r, expectedThreadName));
-
- NettyHttpClient nettyClient
- = (NettyHttpClient) new NettyHttpClientBuilder().eventLoopGroup(eventLoopGroup).build();
-
- assertSame(eventLoopGroup, nettyClient.getBootstrap().config().group());
+ EventLoopGroup eventLoopGroup = new MultiThreadIoEventLoopGroup(1,
+ (Runnable r) -> new Thread(r, expectedThreadName), NioIoHandler.newFactory());
+
+ try {
+ NettyHttpClient nettyClient
+ = (NettyHttpClient) new NettyHttpClientBuilder().eventLoopGroup(eventLoopGroup).build();
+ assertSame(eventLoopGroup, nettyClient.getBootstrap().config().group());
+ } finally {
+ eventLoopGroup.shutdownGracefully(0, 5, TimeUnit.SECONDS).syncUninterruptibly();
+ }
}
@ParameterizedTest
@@ -307,13 +325,27 @@ private static Stream getTimeoutMillisSupplier() {
Arguments.of(Duration.ofNanos(1), TimeUnit.MILLISECONDS.toMillis(1)));
}
+ @Test
+ public void preservesAllocatorAndResolverDefaults() {
+ NettyHttpClient client = (NettyHttpClient) new NettyHttpClientBuilder().build();
+ try {
+ ByteBufAllocator expectedAllocator = System.getProperty("io.netty.allocator.type") == null
+ ? PooledByteBufAllocator.DEFAULT
+ : ByteBufAllocator.DEFAULT;
+ assertSame(expectedAllocator, client.getBootstrap().config().options().get(ChannelOption.ALLOCATOR));
+ assertSame(DefaultAddressResolverGroup.INSTANCE, client.getBootstrap().config().resolver());
+ } finally {
+ client.getBootstrap().config().group().shutdownGracefully(0, 5, TimeUnit.SECONDS).syncUninterruptibly();
+ }
+ }
+
@Test
@EnabledOnOs(OS.WINDOWS)
public void windowsUseNioByDefault() {
NettyHttpClient nettyHttpClient = (NettyHttpClient) new NettyHttpClientBuilder().build();
BootstrapConfig config = nettyHttpClient.getBootstrap().config();
- assertInstanceOf(NioEventLoopGroup.class, config.group());
+ assertTrue(assertInstanceOf(IoEventLoopGroup.class, config.group()).isIoType(NioIoHandler.class));
assertInstanceOf(NioSocketChannel.class, config.channelFactory().newChannel());
}
@@ -323,7 +355,7 @@ public void macUsesKQueueByDefault() {
NettyHttpClient nettyHttpClient = (NettyHttpClient) new NettyHttpClientBuilder().build();
BootstrapConfig config = nettyHttpClient.getBootstrap().config();
- assertInstanceOf(KQueueEventLoopGroup.class, config.group());
+ assertTrue(assertInstanceOf(IoEventLoopGroup.class, config.group()).isIoType(KQueueIoHandler.class));
assertInstanceOf(KQueueSocketChannel.class, config.channelFactory().newChannel());
}
@@ -332,11 +364,11 @@ public void macUsesKQueueByDefault() {
public void macUsesNioIfConfigured() {
NettyHttpClient nettyHttpClient
= (NettyHttpClient) new NettyHttpClientBuilder().channelClass(NioSocketChannel.class)
- .eventLoopGroup(new NioEventLoopGroup())
+ .eventLoopGroup(new MultiThreadIoEventLoopGroup(NioIoHandler.newFactory()))
.build();
BootstrapConfig config = nettyHttpClient.getBootstrap().config();
- assertInstanceOf(NioEventLoopGroup.class, config.group());
+ assertTrue(assertInstanceOf(IoEventLoopGroup.class, config.group()).isIoType(NioIoHandler.class));
assertInstanceOf(NioSocketChannel.class, config.channelFactory().newChannel());
}
@@ -346,7 +378,7 @@ public void linuxUsesEpollByDefault() {
NettyHttpClient nettyHttpClient = (NettyHttpClient) new NettyHttpClientBuilder().build();
BootstrapConfig config = nettyHttpClient.getBootstrap().config();
- assertInstanceOf(EpollEventLoopGroup.class, config.group());
+ assertTrue(assertInstanceOf(IoEventLoopGroup.class, config.group()).isIoType(EpollIoHandler.class));
assertInstanceOf(EpollSocketChannel.class, config.channelFactory().newChannel());
}
@@ -355,24 +387,61 @@ public void linuxUsesEpollByDefault() {
public void linuxUsesNioIfConfigured() {
NettyHttpClient nettyHttpClient
= (NettyHttpClient) new NettyHttpClientBuilder().channelClass(NioSocketChannel.class)
- .eventLoopGroup(new NioEventLoopGroup())
+ .eventLoopGroup(new MultiThreadIoEventLoopGroup(NioIoHandler.newFactory()))
.build();
BootstrapConfig config = nettyHttpClient.getBootstrap().config();
- assertInstanceOf(NioEventLoopGroup.class, config.group());
+ assertTrue(assertInstanceOf(IoEventLoopGroup.class, config.group()).isIoType(NioIoHandler.class));
assertInstanceOf(NioSocketChannel.class, config.channelFactory().newChannel());
}
@ParameterizedTest
@MethodSource("getEventLoopGroupToUseSupplier")
- public void getEventLoopGroupToUse(Class> expected, EventLoopGroup configuredGroup,
- Class extends SocketChannel> configuredChannelClass, boolean isEpollAvailable,
- MethodHandle epollEventLoopGroupCreator, boolean isKqueueAvailable, MethodHandle kqueueEventLoopGroupCreator) {
- EventLoopGroup eventLoopGroup
- = NettyHttpClientBuilder.getEventLoopGroupToUse(configuredGroup, configuredChannelClass, isEpollAvailable,
- epollEventLoopGroupCreator, isKqueueAvailable, kqueueEventLoopGroupCreator);
-
- assertInstanceOf(expected, eventLoopGroup);
+ public void getEventLoopGroupToUse(String expectedTransport, boolean configureGroup,
+ Class extends SocketChannel> configuredChannelClass, boolean isEpollAvailable, boolean epollFails,
+ boolean isKqueueAvailable, boolean kqueueFails) {
+ IoHandlerFactory epollFactory = mockIoHandlerFactory();
+ IoHandlerFactory kqueueFactory = mockIoHandlerFactory();
+ MethodHandle exceptionCreator
+ = MethodHandles.throwException(IoHandlerFactory.class, IllegalStateException.class)
+ .bindTo(new IllegalStateException("Native transport unavailable"));
+ MethodHandle epollCreator
+ = epollFails ? exceptionCreator : MethodHandles.constant(IoHandlerFactory.class, epollFactory);
+ MethodHandle kqueueCreator
+ = kqueueFails ? exceptionCreator : MethodHandles.constant(IoHandlerFactory.class, kqueueFactory);
+ EventLoopGroup configuredGroup
+ = configureGroup ? new MultiThreadIoEventLoopGroup(1, NioIoHandler.newFactory()) : null;
+ EventLoopGroup eventLoopGroup = NettyHttpClientBuilder.getEventLoopGroupToUse(configuredGroup,
+ configuredChannelClass, isEpollAvailable, epollCreator, isKqueueAvailable, kqueueCreator);
+
+ try {
+ assertInstanceOf(MultiThreadIoEventLoopGroup.class, eventLoopGroup);
+ if (configuredGroup != null) {
+ assertSame(configuredGroup, eventLoopGroup);
+ }
+ if ("epoll".equals(expectedTransport)) {
+ verify(epollFactory, atLeastOnce()).newHandler(any());
+ verifyNoInteractions(kqueueFactory);
+ } else if ("kqueue".equals(expectedTransport)) {
+ verify(kqueueFactory, atLeastOnce()).newHandler(any());
+ verifyNoInteractions(epollFactory);
+ } else {
+ verifyNoInteractions(epollFactory, kqueueFactory);
+ }
+ assertTrue(assertInstanceOf(IoEventLoopGroup.class, eventLoopGroup).isIoType(NioIoHandler.class));
+ if (configuredGroup == null) {
+ assertTrue(eventLoopGroup.next()
+ .submit(() -> Thread.currentThread().isDaemon())
+ .syncUninterruptibly()
+ .getNow());
+ assertTrue(eventLoopGroup.next()
+ .submit(() -> Thread.currentThread().getName().startsWith("clientcore-netty-client"))
+ .syncUninterruptibly()
+ .getNow());
+ }
+ } finally {
+ eventLoopGroup.shutdownGracefully(0, 5, TimeUnit.SECONDS).syncUninterruptibly();
+ }
}
@Test
@@ -404,128 +473,60 @@ public void testMaximumHttpVersion() throws NoSuchFieldException, IllegalAccessE
assertEquals(HttpProtocolVersion.HTTP_2, httpVersionField.get(clientv2));
}
- private static Stream getEventLoopGroupToUseSupplier() throws ReflectiveOperationException {
- // Doesn't matter what this is calling, just needs to throw an exception.
- // This will as it doesn't accept the arguments that it will be called with.
- MethodHandle exceptionCreator
- = MethodHandles.publicLookup().unreflectConstructor(NioEventLoopGroup.class.getDeclaredConstructor());
-
- // NOTE: This test doesn't use EpollEventLoopGroup or KQueueEventLoopGroup directly, but rather uses different
- // EventLoopGroup classes as the creation of those requires native libraries to be loaded.
- // This is a workaround to avoid loading the native libraries in the test, as not all OSes can support the
- // native transports.
- MethodHandle epollCreator = MethodHandles.publicLookup()
- .unreflectConstructor(MockEpollEventLoopGroup.class.getDeclaredConstructor(ThreadFactory.class));
- MethodHandle kqueueCreator = MethodHandles.publicLookup()
- .unreflectConstructor(MockKQueueEventLoopGroup.class.getDeclaredConstructor(ThreadFactory.class));
-
- // EventLoopGroup is configured, use it.
- Arguments configuredGroup
- = Arguments.of(NioEventLoopGroup.class, new NioEventLoopGroup(), null, false, null, false, null);
-
- // Epoll is available and nothing is configured, use EpollEventLoopGroup.
- Arguments epollGroup = Arguments.of(MockEpollEventLoopGroup.class, null, null, true, epollCreator, false, null);
-
- // Epoll is available and EpollSocketChannel is configured, use EpollEventLoopGroup.
- Arguments epollChannelGroup = Arguments.of(MockEpollEventLoopGroup.class, null, EpollSocketChannel.class, true,
- epollCreator, false, null);
-
- // Epoll is available but throws an exception, use NioEventLoopGroup.
- Arguments epollExceptionGroup
- = Arguments.of(NioEventLoopGroup.class, null, null, true, exceptionCreator, false, null);
-
- // KQueue is available and nothing is configured, use KQueueEventLoopGroup.
- Arguments kqueueGroup
- = Arguments.of(MockKQueueEventLoopGroup.class, null, null, false, null, true, kqueueCreator);
-
- // KQueue is available and KQueueSocketChannel is configured, use KQueueEventLoopGroup.
- Arguments kqueueChannelGroup = Arguments.of(MockKQueueEventLoopGroup.class, null, KQueueSocketChannel.class,
- false, null, true, kqueueCreator);
-
- // KQueue is available but throws an exception, use NioEventLoopGroup.
- Arguments kqueueExceptionGroup
- = Arguments.of(NioEventLoopGroup.class, null, null, false, null, true, exceptionCreator);
-
- // Both Epoll and KQueue are available, use EpollEventLoopGroup.
- Arguments epollAndKqueueGroup
- = Arguments.of(MockEpollEventLoopGroup.class, null, null, true, epollCreator, true, kqueueCreator);
-
- // Both Epoll and KQueue are available but channel class is set to KQueueSocketChannel, use
- // KQueueEventLoopGroup.
- Arguments epollAndKqueueChannelGroup = Arguments.of(MockKQueueEventLoopGroup.class, null,
- KQueueSocketChannel.class, true, epollCreator, true, kqueueCreator);
-
- // Both Epoll and KQueue are available but throws an exception, use NioEventLoopGroup.
- Arguments epollAndKqueueExceptionGroup
- = Arguments.of(NioEventLoopGroup.class, null, null, true, exceptionCreator, true, exceptionCreator);
-
- // Both Epoll and KQueue are available but channel class is set to EpollSocketChannel, use
- // EpollEventLoopGroup.
- Arguments epollAndKqueueChannelExceptionGroup = Arguments.of(MockEpollEventLoopGroup.class, null,
- EpollSocketChannel.class, true, epollCreator, true, kqueueCreator);
-
- // Both Epoll and KQueue are available but channel class is set to NioSocketChannel, use
- // NioEventLoopGroup.
- Arguments epollAndKqueueChannelNioGroup = Arguments.of(NioEventLoopGroup.class, null, NioSocketChannel.class,
- true, epollCreator, true, kqueueCreator);
-
- return Stream.of(configuredGroup, epollGroup, epollChannelGroup, epollExceptionGroup, kqueueGroup,
- kqueueChannelGroup, kqueueExceptionGroup, epollAndKqueueGroup, epollAndKqueueChannelGroup,
- epollAndKqueueExceptionGroup, epollAndKqueueChannelExceptionGroup, epollAndKqueueChannelNioGroup);
+ private static Stream getEventLoopGroupToUseSupplier() {
+ return Stream.of(Arguments.of("nio", true, null, true, true, true, true),
+ Arguments.of("epoll", false, null, true, false, false, false),
+ Arguments.of("epoll", false, EpollSocketChannel.class, true, false, false, false),
+ Arguments.of("nio", false, null, true, true, false, false),
+ Arguments.of("kqueue", false, null, false, false, true, false),
+ Arguments.of("kqueue", false, KQueueSocketChannel.class, false, false, true, false),
+ Arguments.of("nio", false, null, false, false, true, true),
+ Arguments.of("epoll", false, null, true, false, true, false),
+ Arguments.of("kqueue", false, KQueueSocketChannel.class, true, false, true, false),
+ Arguments.of("kqueue", false, null, true, true, true, false),
+ Arguments.of("nio", false, null, true, true, true, true),
+ Arguments.of("epoll", false, EpollSocketChannel.class, true, false, true, false),
+ Arguments.of("nio", false, NioSocketChannel.class, true, true, true, true),
+ Arguments.of("nio", false, null, false, false, false, false));
}
- public static final class MockEpollEventLoopGroup extends NioEventLoopGroup {
- public MockEpollEventLoopGroup(ThreadFactory threadFactory) {
- super(threadFactory);
- }
- }
-
- public static final class MockKQueueEventLoopGroup extends NioEventLoopGroup {
- public MockKQueueEventLoopGroup(ThreadFactory threadFactory) {
- super(threadFactory);
- }
+ private static IoHandlerFactory mockIoHandlerFactory() {
+ // Delegate to NIO so factory selection can be tested without loading native libraries.
+ IoHandlerFactory delegate = NioIoHandler.newFactory();
+ IoHandlerFactory factory = mock(IoHandlerFactory.class);
+ when(factory.newHandler(any())).thenAnswer(invocation -> delegate.newHandler(invocation.getArgument(0)));
+ return factory;
}
@ParameterizedTest
@MethodSource("getChannelClassSupplier")
public void getChannelClass(Class> expected, Class extends SocketChannel> configuredChannelClass,
- Class extends EventLoopGroup> congiguredGroupClass, boolean isEpollAvailable, boolean isKqueueAvailable) {
+ EventLoopGroup configuredGroup, boolean isEpollAvailable, boolean isKqueueAvailable) {
Class extends Channel> channelClass = NettyHttpClientBuilder.getChannelClass(configuredChannelClass,
- congiguredGroupClass, isEpollAvailable, isKqueueAvailable);
+ configuredGroup, isEpollAvailable, isKqueueAvailable);
assertEquals(expected, channelClass);
}
private static Stream getChannelClassSupplier() {
- // Channel class is configured, use it.
- Arguments configuredChannel = Arguments.of(NioSocketChannel.class, NioSocketChannel.class, null, false, false);
-
- // Epoll is available and EventLoopGroup is EpollEventLoopGroup, use EpollSocketChannel.
- Arguments epollChannel = Arguments.of(EpollSocketChannel.class, null, EpollEventLoopGroup.class, true, false);
-
- // KQueue is available and EventLoopGroup is KQueueEventLoopGroup, use KQueueSocketChannel.
- Arguments kqueueChannel
- = Arguments.of(KQueueSocketChannel.class, null, KQueueEventLoopGroup.class, false, true);
-
- // Epoll is available and EventLoopGroup is NioEventLoopGroup, use NioSocketChannel.
- Arguments epollNioChannel = Arguments.of(NioSocketChannel.class, null, NioEventLoopGroup.class, true, false);
-
- // KQueue is available and EventLoopGroup is NioEventLoopGroup, use NioSocketChannel.
- Arguments kqueueNioChannel = Arguments.of(NioSocketChannel.class, null, NioEventLoopGroup.class, false, true);
-
- // Both Epoll and KQueue are available and EventLoopGroup is NioEventLoopGroup, use NioSocketChannel.
- Arguments epollAndKqueueNioChannel
- = Arguments.of(NioSocketChannel.class, null, NioEventLoopGroup.class, true, true);
-
- // Both Epoll and KQueue are available and EventLoopGroup is EpollEventLoopGroup, use EpollSocketChannel.
- Arguments epollAndKqueueEpollChannel
- = Arguments.of(EpollSocketChannel.class, null, EpollEventLoopGroup.class, true, true);
-
- // Both Epoll and KQueue are available and EventLoopGroup is KQueueEventLoopGroup, use KQueueSocketChannel.
- Arguments epollAndKqueueKqueueChannel
- = Arguments.of(KQueueSocketChannel.class, null, KQueueEventLoopGroup.class, true, true);
+ IoEventLoopGroup nioGroup = mockIoEventLoopGroup(NioIoHandler.class);
+ IoEventLoopGroup epollGroup = mockIoEventLoopGroup(EpollIoHandler.class);
+ IoEventLoopGroup kqueueGroup = mockIoEventLoopGroup(KQueueIoHandler.class);
+
+ return Stream.of(Arguments.of(NioSocketChannel.class, NioSocketChannel.class, epollGroup, true, true),
+ Arguments.of(EpollSocketChannel.class, null, epollGroup, true, false),
+ Arguments.of(KQueueSocketChannel.class, null, kqueueGroup, false, true),
+ Arguments.of(NioSocketChannel.class, null, nioGroup, true, false),
+ Arguments.of(NioSocketChannel.class, null, nioGroup, false, true),
+ Arguments.of(NioSocketChannel.class, null, nioGroup, true, true),
+ Arguments.of(EpollSocketChannel.class, null, epollGroup, true, true),
+ Arguments.of(KQueueSocketChannel.class, null, kqueueGroup, true, true),
+ Arguments.of(NioSocketChannel.class, null, mock(EventLoopGroup.class), true, true));
+ }
- return Stream.of(configuredChannel, epollChannel, kqueueChannel, epollNioChannel, kqueueNioChannel,
- epollAndKqueueNioChannel, epollAndKqueueEpollChannel, epollAndKqueueKqueueChannel);
+ private static IoEventLoopGroup mockIoEventLoopGroup(Class extends IoHandler> ioHandlerClass) {
+ IoEventLoopGroup group = mock(IoEventLoopGroup.class);
+ when(group.isIoType(ioHandlerClass)).thenReturn(true);
+ return group;
}
}
diff --git a/sdk/clientcore/http-netty4/src/test/java/io/clientcore/http/netty4/implementation/Netty4ConnectionPoolTests.java b/sdk/clientcore/http-netty4/src/test/java/io/clientcore/http/netty4/implementation/Netty4ConnectionPoolTests.java
index ba84eb3e9035..25f02cd4d45f 100644
--- a/sdk/clientcore/http-netty4/src/test/java/io/clientcore/http/netty4/implementation/Netty4ConnectionPoolTests.java
+++ b/sdk/clientcore/http-netty4/src/test/java/io/clientcore/http/netty4/implementation/Netty4ConnectionPoolTests.java
@@ -10,7 +10,8 @@
import io.netty.channel.Channel;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
-import io.netty.channel.nio.NioEventLoopGroup;
+import io.netty.channel.MultiThreadIoEventLoopGroup;
+import io.netty.channel.nio.NioIoHandler;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.util.concurrent.Future;
import org.junit.jupiter.api.AfterAll;
@@ -63,7 +64,7 @@ public class Netty4ConnectionPoolTests {
public static void startTestServerAndEventLoopGroup() {
server = NettyHttpClientLocalTestServer.getServer();
server.start();
- eventLoopGroup = new NioEventLoopGroup(2);
+ eventLoopGroup = new MultiThreadIoEventLoopGroup(2, NioIoHandler.newFactory());
bootstrap = new Bootstrap().group(eventLoopGroup).channel(NioSocketChannel.class);
bootstrap.option(ChannelOption.AUTO_READ, false);
SocketAddress socketAddress = new InetSocketAddress("localhost", server.getPort());
diff --git a/sdk/clientcore/http-netty4/src/test/java/io/clientcore/http/netty4/implementation/Netty4UtilityTests.java b/sdk/clientcore/http-netty4/src/test/java/io/clientcore/http/netty4/implementation/Netty4UtilityTests.java
index 468f57acffd0..ffa52f66e01c 100644
--- a/sdk/clientcore/http-netty4/src/test/java/io/clientcore/http/netty4/implementation/Netty4UtilityTests.java
+++ b/sdk/clientcore/http-netty4/src/test/java/io/clientcore/http/netty4/implementation/Netty4UtilityTests.java
@@ -2,15 +2,22 @@
// Licensed under the MIT License.
package io.clientcore.http.netty4.implementation;
+import io.clientcore.core.http.client.HttpProtocolVersion;
import io.clientcore.core.http.models.HttpHeader;
import io.clientcore.core.http.models.HttpHeaderName;
import io.clientcore.core.http.models.HttpHeaders;
import io.clientcore.core.utils.CoreUtils;
+import io.netty.buffer.UnpooledByteBufAllocator;
import io.netty.handler.codec.http.DefaultHttpHeaders;
import io.netty.handler.codec.http.HttpHeaderNames;
+import io.netty.handler.ssl.SslContext;
+import io.netty.handler.ssl.SslProvider;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.Timeout;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.EnumSource;
+import javax.net.ssl.SSLException;
import java.util.Arrays;
import java.util.Map;
import java.util.concurrent.TimeUnit;
@@ -22,11 +29,32 @@
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertLinesMatch;
import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertSame;
import static org.junit.jupiter.api.Assertions.assertTrue;
@Timeout(value = 3, unit = TimeUnit.MINUTES)
public class Netty4UtilityTests {
+ @ParameterizedTest
+ @EnumSource(HttpProtocolVersion.class)
+ public void sslContextEnablesHostnameVerification(HttpProtocolVersion protocolVersion) throws SSLException {
+ SslContext context
+ = Netty4Utility.buildSslContext(protocolVersion, builder -> builder.sslProvider(SslProvider.JDK));
+ assertEquals("HTTPS",
+ context.newEngine(UnpooledByteBufAllocator.DEFAULT, "localhost", 443)
+ .getSSLParameters()
+ .getEndpointIdentificationAlgorithm());
+ }
+
+ @Test
+ public void sslContextHonorsHostnameVerificationModifier() throws SSLException {
+ SslContext context = Netty4Utility.buildSslContext(HttpProtocolVersion.HTTP_1_1,
+ builder -> builder.sslProvider(SslProvider.JDK).endpointIdentificationAlgorithm(null));
+ assertNull(context.newEngine(UnpooledByteBufAllocator.DEFAULT, "localhost", 443)
+ .getSSLParameters()
+ .getEndpointIdentificationAlgorithm());
+ }
+
@Test
public void validateNettyVersionsWithWhatThePomSpecifies() {
Map pomVersions = CoreUtils.getProperties(PROPERTIES_FILE_NAME);
diff --git a/sdk/communication/azure-communication-common/pom.xml b/sdk/communication/azure-communication-common/pom.xml
index cba34ced14f9..0a06e27dadbc 100644
--- a/sdk/communication/azure-communication-common/pom.xml
+++ b/sdk/communication/azure-communication-common/pom.xml
@@ -83,7 +83,7 @@
io.projectreactor
reactor-test
- 3.7.19
+ 3.8.7
test
diff --git a/sdk/core/azure-core-experimental/pom.xml b/sdk/core/azure-core-experimental/pom.xml
index 1ad8ea79775b..0e4b1e740d25 100644
--- a/sdk/core/azure-core-experimental/pom.xml
+++ b/sdk/core/azure-core-experimental/pom.xml
@@ -100,7 +100,7 @@
io.projectreactor
reactor-test
- 3.7.19
+ 3.8.7
test
diff --git a/sdk/core/azure-core-http-jdk-httpclient/pom.xml b/sdk/core/azure-core-http-jdk-httpclient/pom.xml
index f0d76eb2beb4..1c6ea1e4381c 100644
--- a/sdk/core/azure-core-http-jdk-httpclient/pom.xml
+++ b/sdk/core/azure-core-http-jdk-httpclient/pom.xml
@@ -89,7 +89,7 @@