merge of the current 3.0 into the 3.1

merge of the current 3.0 into the 3.1
diff --git a/NOTICE.md b/NOTICE.md
index 1935ed0..4f33066 100644
--- a/NOTICE.md
+++ b/NOTICE.md
@@ -95,7 +95,7 @@
 * Project: http://www.kineticjs.com, https://github.com/ericdrowell/KineticJS

 * Copyright: Eric Rowell

 

-org.objectweb.asm Version 9.7.1

+org.objectweb.asm Version 9.8

 * License: Modified BSD (https://asm.ow2.io/license.html)

 * Copyright (c) 2000-2011 INRIA, France Telecom. All rights reserved.

 

diff --git a/connectors/netty-connector/src/main/java/org/glassfish/jersey/netty/connector/JerseyClientHandler.java b/connectors/netty-connector/src/main/java/org/glassfish/jersey/netty/connector/JerseyClientHandler.java
index 949003f..7f5bb9b 100644
--- a/connectors/netty-connector/src/main/java/org/glassfish/jersey/netty/connector/JerseyClientHandler.java
+++ b/connectors/netty-connector/src/main/java/org/glassfish/jersey/netty/connector/JerseyClientHandler.java
@@ -91,7 +91,7 @@
 
     @Override
     public void channelReadComplete(ChannelHandlerContext ctx) {
-       notifyResponse();
+       notifyResponse(ctx);
     }
 
     @Override
@@ -107,7 +107,7 @@
        }
     }
 
-    protected void notifyResponse() {
+    protected void notifyResponse(ChannelHandlerContext ctx) {
        if (jerseyResponse != null) {
           ClientResponse cr = jerseyResponse;
           jerseyResponse = null;
@@ -146,6 +146,7 @@
                       } else {
                           ClientRequest newReq = new ClientRequest(jerseyRequest);
                           newReq.setUri(newUri);
+                          ctx.close();
                           if (redirectController.prepareRedirect(newReq, cr)) {
                               final NettyConnector newConnector = new NettyConnector(newReq.getClient());
                               newConnector.execute(newReq, redirectUriHistory, new CompletableFuture<ClientResponse>() {
@@ -227,7 +228,7 @@
 
             if (msg instanceof LastHttpContent) {
                 responseDone.complete(null);
-                notifyResponse();
+                notifyResponse(ctx);
             }
         }
     }
diff --git a/connectors/netty-connector/src/main/java/org/glassfish/jersey/netty/connector/JerseyExpectContinueHandler.java b/connectors/netty-connector/src/main/java/org/glassfish/jersey/netty/connector/JerseyExpectContinueHandler.java
index bdede02..6bee4d3 100644
--- a/connectors/netty-connector/src/main/java/org/glassfish/jersey/netty/connector/JerseyExpectContinueHandler.java
+++ b/connectors/netty-connector/src/main/java/org/glassfish/jersey/netty/connector/JerseyExpectContinueHandler.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2023, 2024 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2023, 2025 Oracle and/or its affiliates. All rights reserved.
  *
  * This program and the accompanying materials are made available under the
  * terms of the Eclipse Public License v. 2.0, which is available at
@@ -16,112 +16,133 @@
 
 package org.glassfish.jersey.netty.connector;
 
-import io.netty.channel.Channel;
-import io.netty.channel.ChannelFuture;
 import io.netty.channel.ChannelHandlerContext;
 import io.netty.channel.ChannelInboundHandlerAdapter;
-import io.netty.handler.codec.http.DefaultFullHttpRequest;
-import io.netty.handler.codec.http.HttpHeaderNames;
-import io.netty.handler.codec.http.HttpRequest;
+import io.netty.handler.codec.http.FullHttpMessage;
 import io.netty.handler.codec.http.HttpResponse;
 import io.netty.handler.codec.http.HttpResponseStatus;
-import io.netty.handler.codec.http.HttpUtil;
-import org.glassfish.jersey.client.ClientRequest;
+import io.netty.handler.codec.http.LastHttpContent;
 
 import jakarta.ws.rs.ProcessingException;
+import java.io.IOException;
+import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
-import java.util.concurrent.CompletableFuture;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.TimeUnit;
+import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeoutException;
 
 public class JerseyExpectContinueHandler extends ChannelInboundHandlerAdapter {
 
-    private boolean isExpected;
+    private ExpectationState currentState = ExpectationState.IDLE;
 
-    private static final List<HttpResponseStatus> statusesToBeConsidered = Arrays.asList(HttpResponseStatus.CONTINUE,
-            HttpResponseStatus.UNAUTHORIZED, HttpResponseStatus.EXPECTATION_FAILED,
-            HttpResponseStatus.METHOD_NOT_ALLOWED, HttpResponseStatus.REQUEST_ENTITY_TOO_LARGE);
+    private static final List<HttpResponseStatus> finalErrorStatuses = Arrays.asList(HttpResponseStatus.UNAUTHORIZED,
+            HttpResponseStatus.REQUEST_ENTITY_TOO_LARGE);
+    private static final List<HttpResponseStatus> reSendErrorStatuses = Arrays.asList(
+            HttpResponseStatus.METHOD_NOT_ALLOWED,
+            HttpResponseStatus.EXPECTATION_FAILED);
 
-    private CompletableFuture<HttpResponseStatus> expectedFuture = new CompletableFuture<>();
+    private static final List<HttpResponseStatus> statusesToBeConsidered = new ArrayList<>(reSendErrorStatuses);
+
+    static {
+        statusesToBeConsidered.addAll(finalErrorStatuses);
+        statusesToBeConsidered.add(HttpResponseStatus.CONTINUE);
+    }
+
+    private HttpResponseStatus status = null;
+
+    private CountDownLatch latch = null;
+
+    private boolean propagateLastMessage = false;
 
     @Override
     public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
-        if (isExpected && msg instanceof HttpResponse) {
-            final HttpResponse response = (HttpResponse) msg;
-            if (statusesToBeConsidered.contains(response.status())) {
-                expectedFuture.complete(response.status());
-            }
-            if (!HttpResponseStatus.CONTINUE.equals(response.status())) {
+
+        if (checkExpectResponse(msg) || checkInvalidExpect(msg)) {
+            currentState = ExpectationState.AWAITING;
+        }
+        switch (currentState) {
+            case AWAITING:
+                final HttpResponse response = (HttpResponse) msg;
+                status = response.status();
+                boolean handshakeDone = processErrorStatuses(status) || msg instanceof FullHttpMessage;
+                currentState = (handshakeDone) ? ExpectationState.IDLE : ExpectationState.FINISHING;
+                processLatch();
+                return;
+            case FINISHING:
+                if (msg instanceof LastHttpContent) {
+                    currentState = ExpectationState.IDLE;
+                    if (propagateLastMessage) {
+                        propagateLastMessage = false;
+                        ctx.writeAndFlush(LastHttpContent.EMPTY_LAST_CONTENT);
+                    }
+                }
+                return;
+            default:
                 ctx.fireChannelRead(msg); //bypass the message to the next handler in line
-            } else {
-                ctx.pipeline().remove(JerseyExpectContinueHandler.class);
-            }
-        } else {
-            if (!isExpected
-                    && ctx.pipeline().context(JerseyExpectContinueHandler.class) != null) {
-                ctx.pipeline().remove(JerseyExpectContinueHandler.class);
-            }
-            ctx.fireChannelRead(msg); //bypass the message to the next handler in line
         }
     }
 
-    CompletableFuture<HttpResponseStatus> processExpect100ContinueRequest(HttpRequest nettyRequest,
-                                                                          ClientRequest jerseyRequest,
-                                                                          Channel ch,
-                                                                          Integer timeout)
-            throws InterruptedException, ExecutionException, TimeoutException {
-        //check for 100-Continue presence/availability
-        final Expect100ContinueConnectorExtension expect100ContinueExtension
-                = new Expect100ContinueConnectorExtension();
-
-        final DefaultFullHttpRequest nettyRequestHeaders =
-                new DefaultFullHttpRequest(nettyRequest.protocolVersion(), nettyRequest.method(), nettyRequest.uri());
-        nettyRequestHeaders.headers().setAll(nettyRequest.headers());
-
-        if (!nettyRequestHeaders.headers().contains(HttpHeaderNames.HOST)) {
-            nettyRequestHeaders.headers().add(HttpHeaderNames.HOST, jerseyRequest.getUri().getHost());
+    private boolean checkExpectResponse(Object msg) {
+        if (currentState == ExpectationState.IDLE && latch != null && msg instanceof HttpResponse) {
+            return statusesToBeConsidered.contains(((HttpResponse) msg).status());
         }
-
-        //If Expect:100-continue feature is enabled and client supports it, the nettyRequestHeaders will be
-        //enriched with the 'Expect:100-continue' header.
-        expect100ContinueExtension.invoke(jerseyRequest, nettyRequestHeaders);
-
-        final ChannelFuture expect100ContinueFuture = (HttpUtil.is100ContinueExpected(nettyRequestHeaders))
-                // Send only head of the HTTP request enriched with Expect:100-continue header.
-                ? ch.writeAndFlush(nettyRequestHeaders)
-                // Expect:100-Continue either is not supported or is turned off
-                : null;
-        isExpected = expect100ContinueFuture != null;
-        if (!isExpected) {
-            ch.pipeline().remove(JerseyExpectContinueHandler.class);
-        } else {
-            final HttpResponseStatus status = expectedFuture
-                    .get(timeout, TimeUnit.MILLISECONDS);
-
-            processExpectationStatus(status);
-        }
-        return expectedFuture;
+        return false;
     }
 
-    private void processExpectationStatus(HttpResponseStatus status)
-            throws TimeoutException {
+    private boolean checkInvalidExpect(Object msg) {
+        return (ExpectationState.IDLE.equals(currentState)
+                && msg instanceof HttpResponse
+                && (HttpResponseStatus.CONTINUE.equals(((HttpResponse) msg).status())
+                       || reSendErrorStatuses.contains(((HttpResponse) msg).status()))
+        );
+    }
+
+    boolean processErrorStatuses(HttpResponseStatus status) {
+        if (reSendErrorStatuses.contains(status)) {
+            propagateLastMessage = true;
+        }
+        return (finalErrorStatuses.contains(status));
+    }
+
+    void processExpectationStatus()
+            throws TimeoutException, IOException {
+        if (status == null) {
+            throw new TimeoutException(); // continue without expectations
+        }
         if (!statusesToBeConsidered.contains(status)) {
             throw new ProcessingException(LocalizationMessages
                     .UNEXPECTED_VALUE_FOR_EXPECT_100_CONTINUE_STATUSES(status.code()), null);
         }
-        if (!expectedFuture.isDone() || HttpResponseStatus.EXPECTATION_FAILED.equals(status)) {
-            isExpected = false;
-            throw new TimeoutException(); // continue without expectations
+
+        if (finalErrorStatuses.contains(status)) {
+            throw new IOException(LocalizationMessages
+                    .EXPECT_100_CONTINUE_FAILED_REQUEST_FAILED(), null);
         }
-        if (!HttpResponseStatus.CONTINUE.equals(status)) {
-            throw new ProcessingException(LocalizationMessages
-                    .UNEXPECTED_VALUE_FOR_EXPECT_100_CONTINUE_STATUSES(status.code()), null);
+
+        if (reSendErrorStatuses.contains(status)) {
+            throw new TimeoutException(LocalizationMessages
+                    .EXPECT_100_CONTINUE_FAILED_REQUEST_SHOULD_BE_RESENT()); // Re-send request without expectations
+        }
+
+    }
+
+    void resetHandler() {
+        latch = null;
+    }
+
+    void attachCountDownLatch(CountDownLatch latch) {
+        this.latch = latch;
+    }
+
+    private void processLatch() {
+        if (latch != null) {
+            latch.countDown();
         }
     }
 
-    boolean isExpected() {
-        return isExpected;
+    private enum ExpectationState {
+        AWAITING,
+        FINISHING,
+        IDLE
     }
-}
\ No newline at end of file
+}
diff --git a/connectors/netty-connector/src/main/java/org/glassfish/jersey/netty/connector/NettyConnector.java b/connectors/netty-connector/src/main/java/org/glassfish/jersey/netty/connector/NettyConnector.java
index a4622b8..a65560c 100644
--- a/connectors/netty-connector/src/main/java/org/glassfish/jersey/netty/connector/NettyConnector.java
+++ b/connectors/netty-connector/src/main/java/org/glassfish/jersey/netty/connector/NettyConnector.java
@@ -17,9 +17,7 @@
 package org.glassfish.jersey.netty.connector;
 
 import java.io.IOException;
-import java.io.InterruptedIOException;
 import java.io.OutputStream;
-import java.io.OutputStreamWriter;
 import java.net.InetSocketAddress;
 import java.net.SocketAddress;
 import java.net.URI;
@@ -34,7 +32,6 @@
 import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.CompletionException;
 import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.ExecutionException;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Future;
 import java.util.concurrent.TimeUnit;
@@ -70,6 +67,7 @@
 import io.netty.handler.codec.http.HttpRequest;
 import io.netty.handler.codec.http.HttpUtil;
 import io.netty.handler.codec.http.HttpVersion;
+import io.netty.handler.codec.http.LastHttpContent;
 import io.netty.handler.proxy.HttpProxyHandler;
 import io.netty.handler.proxy.ProxyHandler;
 import io.netty.handler.ssl.ApplicationProtocolConfig;
@@ -257,6 +255,8 @@
                }
             }
 
+            final JerseyExpectContinueHandler expect100ContinueHandler = new JerseyExpectContinueHandler();
+
             if (chan == null) {
                Integer connectTimeout = jerseyRequest.resolveProperty(ClientProperties.CONNECT_TIMEOUT, 0);
                Bootstrap b = new Bootstrap();
@@ -329,8 +329,8 @@
                      final Integer maxInitialLineLength = ClientProperties.getValue(config.getProperties(),
                                 NettyClientProperties.MAX_INITIAL_LINE_LENGTH,
                                 NettyClientProperties.DEFAULT_INITIAL_LINE_LENGTH);
-
                      p.addLast(new HttpClientCodec(maxInitialLineLength, maxHeaderSize, maxChunkSize));
+                     p.addLast(EXPECT_100_CONTINUE_HANDLER, expect100ContinueHandler);
                      p.addLast(new ChunkedWriteHandler());
                      p.addLast(new HttpContentDecompressor());
                     }
@@ -359,11 +359,10 @@
             final Channel ch = chan;
             JerseyClientHandler clientHandler =
                     new JerseyClientHandler(jerseyRequest, responseAvailable, responseDone, redirectUriHistory, this);
-            final JerseyExpectContinueHandler expect100ContinueHandler = new JerseyExpectContinueHandler();
+
             // read timeout makes sense really as an inactivity timeout
             ch.pipeline().addLast(READ_TIMEOUT_HANDLER,
                                   new IdleStateHandler(0, 0, timeout, TimeUnit.MILLISECONDS));
-            ch.pipeline().addLast(EXPECT_100_CONTINUE_HANDLER, expect100ContinueHandler);
             ch.pipeline().addLast(REQUEST_HANDLER, clientHandler);
 
             responseDone.whenComplete((_r, th) -> {
@@ -446,22 +445,11 @@
 //                      // Set later after the entity is "written"
 //                      break;
                 }
-                try {
-                    expect100ContinueHandler.processExpect100ContinueRequest(nettyRequest, jerseyRequest,
-                            ch, expect100ContinueTimeout);
-                } catch (ExecutionException e) {
-                    responseDone.completeExceptionally(e);
-                } catch (TimeoutException e) {
-                    //Expect:100-continue allows timeouts by the spec
-                    //just removing the pipeline from processing
-                    if (ch.pipeline().context(JerseyExpectContinueHandler.class) != null) {
-                        ch.pipeline().remove(EXPECT_100_CONTINUE_HANDLER);
-                    }
-                }
 
                 final CountDownLatch headersSet = new CountDownLatch(1);
                 final CountDownLatch contentLengthSet = new CountDownLatch(1);
 
+
                 jerseyRequest.setStreamProvider(new OutboundMessageContext.StreamProvider() {
                     @Override
                     public OutputStream getOutputStream(int contentLength) throws IOException {
@@ -486,7 +474,6 @@
 
                         try {
                             jerseyRequest.writeEntity();
-
                             if (entityWriter.getType() == NettyEntityWriter.Type.DELAYED) {
                                 nettyRequest.headers().set(HttpHeaderNames.CONTENT_LENGTH, entityWriter.getLength());
                                 contentLengthSet.countDown();
@@ -506,12 +493,36 @@
                 });
 
                 headersSet.await();
-                if (!expect100ContinueHandler.isExpected()) {
-                    // Send the HTTP request. Expect:100-continue processing is not applicable
-                    // in this case.
+                new Expect100ContinueConnectorExtension().invoke(jerseyRequest, nettyRequest);
+
+                boolean continueExpected = HttpUtil.is100ContinueExpected(nettyRequest);
+                boolean expectationsFailed  = false;
+
+                if (continueExpected) {
+                    final CountDownLatch expect100ContinueLatch = new CountDownLatch(1);
+                    expect100ContinueHandler.attachCountDownLatch(expect100ContinueLatch);
+                    //send expect request, sync and wait till either response or timeout received
                     entityWriter.writeAndFlush(nettyRequest);
+                    expect100ContinueLatch.await(expect100ContinueTimeout, TimeUnit.MILLISECONDS);
+                    try {
+                        expect100ContinueHandler.processExpectationStatus();
+                    } catch (TimeoutException e) {
+                        //Expect:100-continue allows timeouts by the spec
+                        //so, send request directly without Expect header.
+                        expectationsFailed = true;
+                    } finally {
+                        //restore request and handler to the original state.
+                        HttpUtil.set100ContinueExpected(nettyRequest, false);
+                        expect100ContinueHandler.resetHandler();
+                    }
                 }
 
+                if (!continueExpected || expectationsFailed) {
+                    if (expectationsFailed) {
+                        ch.pipeline().writeAndFlush(LastHttpContent.EMPTY_LAST_CONTENT).sync();
+                    }
+                    entityWriter.writeAndFlush(nettyRequest);
+                }
                 if (HttpUtil.isTransferEncodingChunked(nettyRequest)) {
                     entityWriter.write(new HttpChunkedInput(entityWriter.getChunkedInput()));
                 } else {
diff --git a/connectors/netty-connector/src/main/java/org/glassfish/jersey/netty/connector/internal/JerseyChunkedInput.java b/connectors/netty-connector/src/main/java/org/glassfish/jersey/netty/connector/internal/JerseyChunkedInput.java
index 4ffe52e..baa9118 100644
--- a/connectors/netty-connector/src/main/java/org/glassfish/jersey/netty/connector/internal/JerseyChunkedInput.java
+++ b/connectors/netty-connector/src/main/java/org/glassfish/jersey/netty/connector/internal/JerseyChunkedInput.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, 2024 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2025 Oracle and/or its affiliates. All rights reserved.
  *
  * This program and the accompanying materials are made available under the
  * terms of the Eclipse Public License v. 2.0, which is available at
@@ -68,7 +68,8 @@
         ByteBuffer peek = queue.peek();
 
         if ((peek != null && peek == VOID)) {
-            queue.remove(); // VOID from the top.
+            //required for JDK 11 and netty.version = 4.1.121.Final
+            queue.poll(); // VOID from the top.
             open = false;
             removeCloseListener();
             return true;
diff --git a/connectors/netty-connector/src/main/resources/org/glassfish/jersey/netty/connector/localization.properties b/connectors/netty-connector/src/main/resources/org/glassfish/jersey/netty/connector/localization.properties
index 7d6f9fc..dd5de49 100644
--- a/connectors/netty-connector/src/main/resources/org/glassfish/jersey/netty/connector/localization.properties
+++ b/connectors/netty-connector/src/main/resources/org/glassfish/jersey/netty/connector/localization.properties
@@ -1,5 +1,5 @@
 #
-# Copyright (c) 2016, 2023 Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2016, 2025 Oracle and/or its affiliates. All rights reserved.
 #
 # This program and the accompanying materials are made available under the
 # terms of the Eclipse Public License v. 2.0, which is available at
@@ -23,3 +23,5 @@
 redirect.infinite.loop="Infinite loop in chained redirects detected."
 redirect.limit.reached="Max chained redirect limit ({0}) exceeded."
 unexpected.value.for.expect.100.continue.statuses=Unexpected value: ("{0}").
+expect.100.continue.failed.request.should.be.resent=Expect 100-continue failed. Request should be resent.
+expect.100.continue.failed.request.failed=Expect 100-continue failed. Request failed.
diff --git a/containers/jdk-http/pom.xml b/containers/jdk-http/pom.xml
index a1b3b99..abb6ca0 100644
--- a/containers/jdk-http/pom.xml
+++ b/containers/jdk-http/pom.xml
@@ -34,12 +34,6 @@
 
     <dependencies>
         <dependency>
-            <groupId>commons-io</groupId>
-            <artifactId>commons-io</artifactId>
-            <scope>test</scope>
-            <version>${commons.io.version}</version>
-        </dependency>
-        <dependency>
             <groupId>org.hamcrest</groupId>
             <artifactId>hamcrest</artifactId>
             <scope>test</scope>
diff --git a/containers/jdk-http/src/test/java/org/glassfish/jersey/jdkhttp/JdkHttpsServerTest.java b/containers/jdk-http/src/test/java/org/glassfish/jersey/jdkhttp/JdkHttpsServerTest.java
index 2b912d8..a0d978b 100644
--- a/containers/jdk-http/src/test/java/org/glassfish/jersey/jdkhttp/JdkHttpsServerTest.java
+++ b/containers/jdk-http/src/test/java/org/glassfish/jersey/jdkhttp/JdkHttpsServerTest.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2023 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2025 Oracle and/or its affiliates. All rights reserved.
  *
  * This program and the accompanying materials are made available under the
  * terms of the Eclipse Public License v. 2.0, which is available at
@@ -30,9 +30,9 @@
 import javax.net.ssl.SSLContext;
 import javax.net.ssl.SSLHandshakeException;
 
-import org.apache.commons.io.IOUtils;
 import org.glassfish.jersey.SslConfigurator;
 import org.glassfish.jersey.internal.util.JdkVersion;
+import org.glassfish.jersey.message.internal.ReaderWriter;
 import org.glassfish.jersey.server.ResourceConfig;
 
 import org.junit.jupiter.api.AfterEach;
@@ -195,9 +195,9 @@
 
 
         final SslConfigurator sslConfigClient = SslConfigurator.newInstance()
-                .trustStoreBytes(IOUtils.toByteArray(trustStore))
+                .trustStoreBytes(ReaderWriter.readFromAsBytes(trustStore))
                 .trustStorePassword(TRUSTSTORE_CLIENT_PWD)
-                .keyStoreBytes(IOUtils.toByteArray(keyStore))
+                .keyStoreBytes(ReaderWriter.readFromAsBytes(keyStore))
                 .keyPassword(KEYSTORE_CLIENT_PWD);
 
         return sslConfigClient.createSSLContext();
@@ -208,9 +208,9 @@
         final InputStream keyStore = JdkHttpsServerTest.class.getResourceAsStream(KEYSTORE_SERVER_FILE);
 
         final SslConfigurator sslConfigServer = SslConfigurator.newInstance()
-                .keyStoreBytes(IOUtils.toByteArray(keyStore))
+                .keyStoreBytes(ReaderWriter.readFromAsBytes(keyStore))
                 .keyPassword(KEYSTORE_SERVER_PWD)
-                .trustStoreBytes(IOUtils.toByteArray(trustStore))
+                .trustStoreBytes(ReaderWriter.readFromAsBytes(trustStore))
                 .trustStorePassword(TRUSTSTORE_SERVER_PWD);
 
         return sslConfigServer.createSSLContext();
diff --git a/containers/jersey-servlet-core/src/main/java/org/glassfish/jersey/servlet/WebComponent.java b/containers/jersey-servlet-core/src/main/java/org/glassfish/jersey/servlet/WebComponent.java
index e6f5155..f35c720 100644
--- a/containers/jersey-servlet-core/src/main/java/org/glassfish/jersey/servlet/WebComponent.java
+++ b/containers/jersey-servlet-core/src/main/java/org/glassfish/jersey/servlet/WebComponent.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2024 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2025 Oracle and/or its affiliates. All rights reserved.
  *
  * This program and the accompanying materials are made available under the
  * terms of the Eclipse Public License v. 2.0, which is available at
@@ -38,6 +38,7 @@
 import java.util.logging.Logger;
 import java.util.stream.Collectors;
 
+import jakarta.servlet.ServletInputStream;
 import jakarta.ws.rs.RuntimeType;
 import jakarta.ws.rs.core.Form;
 import jakarta.ws.rs.core.GenericType;
@@ -425,13 +426,18 @@
 
         try {
             requestContext.setEntityStream(new InputStreamWrapper() {
+
+                private ServletInputStream wrappedStream;
                 @Override
                 protected InputStream getWrapped() {
-                    try {
-                        return servletRequest.getInputStream();
-                    } catch (IOException e) {
-                        throw new UncheckedIOException(e);
+                    if (wrappedStream == null) {
+                        try {
+                            wrappedStream = servletRequest.getInputStream();
+                        } catch (IOException e) {
+                            throw new UncheckedIOException(e);
+                        }
                     }
+                    return wrappedStream;
                 }
             });
         } catch (UncheckedIOException e) {
diff --git a/containers/jersey-servlet-core/src/main/java/org/glassfish/jersey/servlet/internal/ResponseWriter.java b/containers/jersey-servlet-core/src/main/java/org/glassfish/jersey/servlet/internal/ResponseWriter.java
index 9876c01..6538a9e 100644
--- a/containers/jersey-servlet-core/src/main/java/org/glassfish/jersey/servlet/internal/ResponseWriter.java
+++ b/containers/jersey-servlet-core/src/main/java/org/glassfish/jersey/servlet/internal/ResponseWriter.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2024 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2025 Oracle and/or its affiliates. All rights reserved.
  *
  * This program and the accompanying materials are made available under the
  * terms of the Eclipse Public License v. 2.0, which is available at
@@ -115,6 +115,10 @@
     @Override
     public OutputStream writeResponseStatusAndHeaders(final long contentLength, final ContainerResponse responseContext)
             throws ContainerException {
+        if (asyncExt.isCompleted()) {
+            return null;
+        }
+
         this.responseContext.complete(responseContext);
 
         // first set the content length, so that if headers have an explicit value, it takes precedence over this one
diff --git a/containers/jersey-servlet-core/src/main/java/org/glassfish/jersey/servlet/spi/AsyncContextDelegate.java b/containers/jersey-servlet-core/src/main/java/org/glassfish/jersey/servlet/spi/AsyncContextDelegate.java
index 5825375..2652e62 100644
--- a/containers/jersey-servlet-core/src/main/java/org/glassfish/jersey/servlet/spi/AsyncContextDelegate.java
+++ b/containers/jersey-servlet-core/src/main/java/org/glassfish/jersey/servlet/spi/AsyncContextDelegate.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2021 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2025 Oracle and/or its affiliates. All rights reserved.
  *
  * This program and the accompanying materials are made available under the
  * terms of the Eclipse Public License v. 2.0, which is available at
@@ -42,4 +42,17 @@
      * Invoked upon a response writing completion when the response write is either committed or canceled.
      */
     public void complete();
+
+    /**
+     * <p>
+     *     Return {@code true} when the AsyncContext is completed, such as when {@link #complete()} has been called.
+     * </p>
+     * <p>
+     *     For compatibility, the default is {@code false}.
+     * </p>
+     * @return {@code true} when the AsyncContext is completed.
+     */
+    public default boolean isCompleted() {
+        return false;
+    }
 }
diff --git a/containers/jersey-servlet/src/main/java/org/glassfish/jersey/servlet/async/AsyncContextDelegateProviderImpl.java b/containers/jersey-servlet/src/main/java/org/glassfish/jersey/servlet/async/AsyncContextDelegateProviderImpl.java
index efe248e..89fa99a 100644
--- a/containers/jersey-servlet/src/main/java/org/glassfish/jersey/servlet/async/AsyncContextDelegateProviderImpl.java
+++ b/containers/jersey-servlet/src/main/java/org/glassfish/jersey/servlet/async/AsyncContextDelegateProviderImpl.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2021 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2025 Oracle and/or its affiliates. All rights reserved.
  *
  * This program and the accompanying materials are made available under the
  * terms of the Eclipse Public License v. 2.0, which is available at
@@ -16,12 +16,15 @@
 
 package org.glassfish.jersey.servlet.async;
 
+import java.io.IOException;
 import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.concurrent.atomic.AtomicReference;
 import java.util.logging.Level;
 import java.util.logging.Logger;
 
 import jakarta.servlet.AsyncContext;
+import jakarta.servlet.AsyncEvent;
+import jakarta.servlet.AsyncListener;
 import jakarta.servlet.http.HttpServletRequest;
 import jakarta.servlet.http.HttpServletResponse;
 
@@ -70,7 +73,32 @@
         public void suspend() throws IllegalStateException {
             // Suspend only if not completed and not suspended before.
             if (!completed.get() && asyncContextRef.get() == null) {
-                asyncContextRef.set(getAsyncContext());
+                final AsyncContext asyncContext = getAsyncContext();
+                asyncContext.addListener(new CompletedAsyncContextListener());
+                asyncContextRef.set(asyncContext);
+            }
+        }
+
+        private class CompletedAsyncContextListener implements AsyncListener {
+
+            @Override
+            public void onComplete(AsyncEvent event) throws IOException {
+                complete();
+            }
+
+            @Override
+            public void onTimeout(AsyncEvent event) throws IOException {
+
+            }
+
+            @Override
+            public void onError(AsyncEvent event) throws IOException {
+                complete();
+            }
+
+            @Override
+            public void onStartAsync(AsyncEvent event) throws IOException {
+
             }
         }
 
@@ -102,5 +130,10 @@
                 asyncContext.complete();
             }
         }
+
+        @Override
+        public boolean isCompleted() {
+            return completed.get();
+        }
     }
 }
diff --git a/containers/jersey-servlet/src/test/java/org/glassfish/jersey/servlet/async/AsyncContextClosedTest.java b/containers/jersey-servlet/src/test/java/org/glassfish/jersey/servlet/async/AsyncContextClosedTest.java
new file mode 100644
index 0000000..220d832
--- /dev/null
+++ b/containers/jersey-servlet/src/test/java/org/glassfish/jersey/servlet/async/AsyncContextClosedTest.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2025 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package org.glassfish.jersey.servlet.async;
+
+import org.glassfish.jersey.server.spi.ContainerResponseWriter;
+import org.glassfish.jersey.servlet.internal.ResponseWriter;
+import org.junit.jupiter.api.Test;
+
+import jakarta.servlet.AsyncContext;
+import jakarta.servlet.AsyncListener;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.Executors;
+import java.util.concurrent.TimeUnit;
+
+public class AsyncContextClosedTest {
+    @Test
+    public void testClosedAsyncContext() {
+        List<AsyncListener> asyncListeners = new ArrayList<>(1);
+        AsyncContext async = (AsyncContext) Proxy.newProxyInstance(getClass().getClassLoader(),
+                new Class[]{AsyncContext.class}, new InvocationHandler() {
+                    @Override
+                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
+                        switch (method.getName()) {
+                            case "addListener":
+                                asyncListeners.add((AsyncListener) args[0]);
+                                break;
+                            case "complete":
+                                asyncListeners.forEach((asyncListener -> {
+                                    try {
+                                        asyncListener.onComplete(null);
+                                    } catch (IOException e) {
+                                        throw new RuntimeException(e);
+                                    }
+                                }));
+                        }
+                        return null;
+                    }
+                });
+
+        HttpServletRequest request = (HttpServletRequest) Proxy.newProxyInstance(getClass().getClassLoader(),
+                new Class[]{HttpServletRequest.class}, new InvocationHandler() {
+                    boolean asyncStarted = false;
+
+                    @Override
+                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
+                        switch (method.getName()) {
+                            case "isAsyncStarted":
+                                return asyncStarted;
+                            case "startAsync":
+                                asyncStarted = true;
+                                return async;
+                            case "getAsyncContext":
+                                return async;
+
+                        }
+                        return null;
+                    }
+                });
+
+        HttpServletResponse response = (HttpServletResponse) Proxy.newProxyInstance(getClass().getClassLoader(),
+                new Class[]{HttpServletResponse.class}, new InvocationHandler() {
+                    @Override
+                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
+                        return null;
+                    }
+                });
+
+        // Create writer
+        ResponseWriter writer = new ResponseWriter(false, false, response,
+                new AsyncContextDelegateProviderImpl().createDelegate(request, response),
+                Executors.newSingleThreadScheduledExecutor());
+        writer.suspend(10, TimeUnit.SECONDS, new ContainerResponseWriter.TimeoutHandler() {
+            @Override
+            public void onTimeout(ContainerResponseWriter responseWriter) {
+                throw new IllegalStateException();
+            }
+        });
+        // Simulate completion by the Servlet Container;
+        request.getAsyncContext().complete();
+        // Check write is ignored
+        writer.writeResponseStatusAndHeaders(10, null);
+    }
+}
diff --git a/core-client/pom.xml b/core-client/pom.xml
index 4630b07..34a1e33 100644
--- a/core-client/pom.xml
+++ b/core-client/pom.xml
@@ -144,6 +144,12 @@
         </dependency>
 
         <dependency>
+            <groupId>jakarta.xml.bind</groupId>
+            <artifactId>jakarta.xml.bind-api</artifactId>
+            <scope>test</scope>
+        </dependency>
+
+        <dependency>
             <groupId>org.glassfish.jersey.inject</groupId>
             <artifactId>jersey-hk2</artifactId>
             <version>${project.version}</version>
diff --git a/core-client/src/main/java/org/glassfish/jersey/client/ClientResponse.java b/core-client/src/main/java/org/glassfish/jersey/client/ClientResponse.java
index 9491741..698fb39 100644
--- a/core-client/src/main/java/org/glassfish/jersey/client/ClientResponse.java
+++ b/core-client/src/main/java/org/glassfish/jersey/client/ClientResponse.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2020 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2025 Oracle and/or its affiliates. All rights reserved.
  *
  * This program and the accompanying materials are made available under the
  * terms of the Eclipse Public License v. 2.0, which is available at
@@ -22,6 +22,7 @@
 import java.io.InputStream;
 import java.io.OutputStream;
 import java.lang.annotation.Annotation;
+import java.lang.reflect.Type;
 import java.net.URI;
 import java.util.Collections;
 import java.util.Map;
@@ -62,8 +63,12 @@
      * @param response       JAX-RS response to be used to initialize the response context.
      */
     public ClientResponse(final ClientRequest requestContext, final Response response) {
-        this(response.getStatusInfo(), requestContext);
-        this.headers(OutboundJaxrsResponse.from(response, requestContext.getConfiguration()).getContext().getStringHeaders());
+        super(requestContext.getConfiguration(),
+                OutboundJaxrsResponse.from(response, requestContext.getConfiguration()).getContext().getStringHeaders(),
+                false
+        );
+        this.requestContext = requestContext;
+        init(response.getStatusInfo(), requestContext, requestContext.getUri());
 
         final Object entity = response.getEntity();
         if (entity != null) {
@@ -77,18 +82,19 @@
                         ByteArrayOutputStream baos = new ByteArrayOutputStream();
                         OutputStream stream = null;
                         try {
-                            try {
-                                stream = requestContext.getWorkers().writeTo(
-                                        entity, entity.getClass(), null, null, response.getMediaType(),
-                                        response.getMetadata(), requestContext.getPropertiesDelegate(), baos,
-                                        Collections.<WriterInterceptor>emptyList());
-                            } finally {
-                                if (stream != null) {
-                                    stream.close();
-                                }
-                            }
+                            final Type t = response instanceof OutboundJaxrsResponse
+                                    ? ((OutboundJaxrsResponse) response).getContext().getEntityType()
+                                    : null;
+                            stream = requestContext.getWorkers().writeTo(
+                                    entity, entity.getClass(), t, null, response.getMediaType(),
+                                    response.getMetadata(), requestContext.getPropertiesDelegate(), baos,
+                                    Collections.<WriterInterceptor>emptyList());
                         } catch (IOException e) {
                             // ignore
+                        } finally {
+                            if (stream != null) {
+                                stream.close();
+                            }
                         }
 
                         byteArrayInputStream = new ByteArrayInputStream(baos.toByteArray());
@@ -120,10 +126,13 @@
      */
     public ClientResponse(Response.StatusType status, ClientRequest requestContext, URI resolvedRequestUri) {
         super(requestContext.getConfiguration());
+        this.requestContext = requestContext;
+        init(status, requestContext, resolvedRequestUri);
+    }
+
+    private void init(Response.StatusType status, ClientRequest requestContext, URI resolvedRequestUri) {
         this.status = status;
         this.resolvedUri = resolvedRequestUri;
-        this.requestContext = requestContext;
-
         setWorkers(requestContext.getWorkers());
     }
 
diff --git a/core-client/src/main/java/org/glassfish/jersey/client/authentication/BasicAuthenticator.java b/core-client/src/main/java/org/glassfish/jersey/client/authentication/BasicAuthenticator.java
index 9637066..d38fc2b 100644
--- a/core-client/src/main/java/org/glassfish/jersey/client/authentication/BasicAuthenticator.java
+++ b/core-client/src/main/java/org/glassfish/jersey/client/authentication/BasicAuthenticator.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2020 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2025 Oracle and/or its affiliates. All rights reserved.
  *
  * This program and the accompanying materials are made available under the
  * terms of the Eclipse Public License v. 2.0, which is available at
@@ -17,8 +17,8 @@
 package org.glassfish.jersey.client.authentication;
 
 import java.util.Base64;
+import java.util.List;
 import java.util.Locale;
-import java.util.logging.Level;
 import java.util.logging.Logger;
 
 import jakarta.ws.rs.client.ClientRequestContext;
@@ -96,20 +96,22 @@
      * @throws ResponseAuthenticationException in case that basic credentials missing or are in invalid format
      */
     public boolean filterResponseAndAuthenticate(ClientRequestContext request, ClientResponseContext response) {
-        final String authenticate = response.getHeaders().getFirst(HttpHeaders.WWW_AUTHENTICATE);
-        if (authenticate != null && authenticate.trim().toUpperCase(Locale.ROOT).startsWith("BASIC")) {
-            HttpAuthenticationFilter.Credentials credentials = HttpAuthenticationFilter
-                    .getCredentials(request, defaultCredentials, HttpAuthenticationFilter.Type.BASIC);
-
-            if (credentials == null) {
-                if (response.hasEntity()) {
-                    AuthenticationUtil.discardInputAndClose(response.getEntityStream());
-                }
-                throw new ResponseAuthenticationException(null, LocalizationMessages.AUTHENTICATION_CREDENTIALS_MISSING_BASIC());
-            }
-
-            return HttpAuthenticationFilter.repeatRequest(request, response, calculateAuthentication(credentials));
+        final List<String> authHeaders = response.getHeaders().get(HttpHeaders.WWW_AUTHENTICATE);
+        if (authHeaders == null || authHeaders.size() == 0 || authHeaders.stream()
+                .noneMatch(h -> h != null && h.toUpperCase(Locale.ROOT).startsWith("BASIC"))) {
+            return false;
         }
-        return false;
+
+        HttpAuthenticationFilter.Credentials credentials = HttpAuthenticationFilter
+                .getCredentials(request, defaultCredentials, HttpAuthenticationFilter.Type.BASIC);
+
+        if (credentials == null) {
+            if (response.hasEntity()) {
+                AuthenticationUtil.discardInputAndClose(response.getEntityStream());
+            }
+            throw new ResponseAuthenticationException(null, LocalizationMessages.AUTHENTICATION_CREDENTIALS_MISSING_BASIC());
+        }
+
+        return HttpAuthenticationFilter.repeatRequest(request, response, calculateAuthentication(credentials));
     }
 }
diff --git a/core-client/src/main/java/org/glassfish/jersey/client/innate/http/SSLParamConfigurator.java b/core-client/src/main/java/org/glassfish/jersey/client/innate/http/SSLParamConfigurator.java
index 79dc60e..67d4a63 100644
--- a/core-client/src/main/java/org/glassfish/jersey/client/innate/http/SSLParamConfigurator.java
+++ b/core-client/src/main/java/org/glassfish/jersey/client/innate/http/SSLParamConfigurator.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2023, 2024 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2023, 2025 Oracle and/or its affiliates. All rights reserved.
  *
  * This program and the accompanying materials are made available under the
  * terms of the Eclipse Public License v. 2.0, which is available at
@@ -20,12 +20,14 @@
 import org.glassfish.jersey.client.ClientRequest;
 import org.glassfish.jersey.http.HttpHeaders;
 import org.glassfish.jersey.internal.PropertiesResolver;
+import org.glassfish.jersey.internal.guava.InetAddresses;
 
 import javax.net.ssl.SSLEngine;
 import javax.net.ssl.SSLParameters;
 import javax.net.ssl.SSLSocket;
 import jakarta.ws.rs.core.Configuration;
 import jakarta.ws.rs.core.UriBuilder;
+import java.net.Inet6Address;
 import java.net.InetAddress;
 import java.net.URI;
 import java.net.UnknownHostException;
@@ -233,7 +235,9 @@
         String host = uri.getHost();
         try {
             InetAddress ip = InetAddress.getByName(host);
-            return UriBuilder.fromUri(uri).host(ip.getHostAddress()).build();
+            // ipv6 is expected in square brackets in UriBuilder#host()
+            final String hostAddress = ip instanceof Inet6Address ? '[' + ip.getHostAddress() + ']' : ip.getHostAddress();
+            return UriBuilder.fromUri(uri).host(hostAddress).build();
         } catch (UnknownHostException e) {
             return uri;
         }
diff --git a/core-client/src/main/java/org/glassfish/jersey/client/innate/http/SniConfigurator.java b/core-client/src/main/java/org/glassfish/jersey/client/innate/http/SniConfigurator.java
index baf1c28..4bd2856 100644
--- a/core-client/src/main/java/org/glassfish/jersey/client/innate/http/SniConfigurator.java
+++ b/core-client/src/main/java/org/glassfish/jersey/client/innate/http/SniConfigurator.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2023, 2024 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2023, 2025 Oracle and/or its affiliates. All rights reserved.
  *
  * This program and the accompanying materials are made available under the
  * terms of the Eclipse Public License v. 2.0, which is available at
@@ -60,7 +60,10 @@
     static Optional<SniConfigurator> createWhenHostHeader(URI hostUri, String sniHost, boolean whenDiffer) {
         final String trimmedHeader;
         if (sniHost != null) {
-            int index = sniHost.indexOf(':'); // RFC 7230  Host = uri-host [ ":" port ] ;
+            int index = sniHost.lastIndexOf(':'); // RFC 7230  Host = uri-host [ ":" port ] ;
+            if (sniHost.indexOf(']', index) != -1) {
+                index = -1; // beware of ipv6 [:1] without port
+            }
             final String trimmedHeader0 = index != -1 ? sniHost.substring(0, index).trim() : sniHost.trim();
             trimmedHeader = trimmedHeader0.isEmpty() ? sniHost : trimmedHeader0;
         } else {
diff --git a/core-client/src/test/java/org/glassfish/jersey/client/AbortTest.java b/core-client/src/test/java/org/glassfish/jersey/client/AbortTest.java
new file mode 100644
index 0000000..1bac330
--- /dev/null
+++ b/core-client/src/test/java/org/glassfish/jersey/client/AbortTest.java
@@ -0,0 +1,311 @@
+/*
+ * Copyright (c) 2025 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package org.glassfish.jersey.client;
+
+import jakarta.ws.rs.SeBootstrap;
+import jakarta.ws.rs.core.EntityPart;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+import jakarta.ws.rs.Priorities;
+import jakarta.ws.rs.Produces;
+import jakarta.ws.rs.WebApplicationException;
+import jakarta.ws.rs.client.Client;
+import jakarta.ws.rs.client.ClientBuilder;
+import jakarta.ws.rs.client.ClientRequestContext;
+import jakarta.ws.rs.client.ClientRequestFilter;
+import jakarta.ws.rs.client.ClientResponseContext;
+import jakarta.ws.rs.client.ClientResponseFilter;
+import jakarta.ws.rs.core.Application;
+import jakarta.ws.rs.core.GenericEntity;
+import jakarta.ws.rs.core.Link;
+import jakarta.ws.rs.core.MediaType;
+import jakarta.ws.rs.core.MultivaluedMap;
+import jakarta.ws.rs.core.Response;
+import jakarta.ws.rs.core.UriBuilder;
+import jakarta.ws.rs.core.Variant;
+import jakarta.ws.rs.ext.MessageBodyWriter;
+import jakarta.ws.rs.ext.ReaderInterceptor;
+import jakarta.ws.rs.ext.ReaderInterceptorContext;
+import jakarta.ws.rs.ext.RuntimeDelegate;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.CompletionStage;
+import java.util.concurrent.atomic.AtomicReference;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+public class AbortTest {
+    private static final String TEXT_CSV = "text/csv";
+    private static final String TEXT_HEADER = "text/header";
+    private static final String EXPECTED_CSV = "hello;goodbye\nsalutations;farewell";
+    private static final List<List<String>> CSV_LIST = Arrays.asList(
+            Arrays.asList("hello", "goodbye"),
+            Arrays.asList("salutations", "farewell")
+    );
+    private final String entity = "HI";
+    private final String header = "CUSTOM_HEADER";
+
+
+    @Test
+    void testAbortWithGenericEntity() {
+        Client client = ClientBuilder.newBuilder()
+                .register(AbortRequestFilter.class)
+                .register(CsvWriter.class)
+                .build();
+        String csvString = client.target("http://localhost:8080")
+                .request(TEXT_CSV)
+                .get(String.class);
+        assertEquals(EXPECTED_CSV, csvString);
+        client.close();
+    }
+
+    public static class AbortRequestFilter implements ClientRequestFilter {
+
+        @Override
+        public void filter(ClientRequestContext requestContext) {
+            requestContext.abortWith(Response.ok(new GenericEntity<List<List<String>>>(CSV_LIST) {
+            }).type(TEXT_CSV).build());
+        }
+    }
+
+    @Produces(TEXT_CSV)
+    public static class CsvWriter implements MessageBodyWriter<List<List<String>>> {
+
+        @Override
+        public boolean isWriteable(Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) {
+            return List.class.isAssignableFrom(type) && genericType instanceof ParameterizedType
+                    && ((ParameterizedType) genericType).getActualTypeArguments()[0] instanceof ParameterizedType
+                    && String.class.equals(((ParameterizedType) ((ParameterizedType) genericType).getActualTypeArguments()[0])
+                        .getActualTypeArguments()[0]);
+        }
+
+        @Override
+        public void writeTo(List<List<String>> csvList, Class<?> type, Type genericType, Annotation[] annotations,
+                            MediaType mediaType, MultivaluedMap<String, Object> httpHeaders, OutputStream entityStream)
+                throws IOException, WebApplicationException {
+            List<String> rows = new ArrayList<>();
+            for (List<String> row : csvList) {
+                rows.add(String.join(";", row));
+            }
+            String csv = String.join("\n", rows);
+
+            entityStream.write(csv.getBytes(StandardCharsets.UTF_8));
+            entityStream.flush();
+        }
+    }
+
+    @Test
+    void testAbortWithMBWWritingHeaders() {
+        try (Response response = ClientBuilder.newClient().register(new ClientRequestFilter() {
+            @Override
+            public void filter(ClientRequestContext requestContext) throws IOException {
+                requestContext.abortWith(Response.ok(entity, TEXT_HEADER).build());
+            }
+        }).register(new MessageBodyWriter<String>() {
+
+            @Override
+            public boolean isWriteable(Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) {
+                return mediaType.toString().equals(TEXT_HEADER);
+            }
+
+            @Override
+            public void writeTo(String s, Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType,
+                                MultivaluedMap<String, Object> httpHeaders, OutputStream entityStream) throws IOException,
+                    WebApplicationException {
+                httpHeaders.add(header, entity);
+                entityStream.write(s.getBytes());
+            }
+        }, Priorities.USER - 1).target("http://localhost:8080").request().get()) {
+            Assertions.assertEquals(entity, response.readEntity(String.class));
+            Assertions.assertEquals(entity, response.getHeaderString(header));
+        }
+    }
+
+    @Test
+    void testInterceptorHeaderAdd() {
+        final String header2 = "CUSTOM_HEADER_2";
+
+        try (Response response = ClientBuilder.newClient().register(new ClientRequestFilter() {
+            @Override
+            public void filter(ClientRequestContext requestContext) throws IOException {
+                requestContext.abortWith(Response.ok().entity(entity).build());
+            }
+        }).register(new ReaderInterceptor() {
+                    @Override
+                    public Object aroundReadFrom(ReaderInterceptorContext context) throws IOException, WebApplicationException {
+                        MultivaluedMap<String, String> headers = context.getHeaders();
+                        headers.put(header, Collections.singletonList(entity));
+                        headers.add(header2, entity);
+                        return context.proceed();
+                    }
+                })
+                .target("http://localhost:8080").request().get()) {
+            Assertions.assertEquals(entity, response.readEntity(String.class));
+            Assertions.assertEquals(entity, response.getHeaderString(header));
+            Assertions.assertEquals(entity, response.getHeaderString(header2));
+        }
+    }
+
+    @Test
+    void testInterceptorHeaderIterate() {
+        final AtomicReference<String> originalHeader = new AtomicReference<>();
+
+        try (Response response = ClientBuilder.newClient().register(new ClientRequestFilter() {
+                    @Override
+                    public void filter(ClientRequestContext requestContext) throws IOException {
+                        requestContext.abortWith(Response.ok().header(header, header).entity(entity).build());
+                    }
+                }).register(new ReaderInterceptor() {
+                    @Override
+                    public Object aroundReadFrom(ReaderInterceptorContext context) throws IOException, WebApplicationException {
+                        MultivaluedMap<String, String> headers = context.getHeaders();
+                        Iterator<Map.Entry<String, List<String>>> it = headers.entrySet().iterator();
+                        while (it.hasNext()) {
+                            Map.Entry<String, List<String>> next = it.next();
+                            if (header.equals(next.getKey())) {
+                                originalHeader.set(next.setValue(Collections.singletonList(entity)).get(0));
+                            }
+                        }
+                        return context.proceed();
+                    }
+                })
+                .target("http://localhost:8080").request().get()) {
+            Assertions.assertEquals(entity, response.readEntity(String.class));
+            Assertions.assertEquals(entity, response.getHeaderString(header));
+            Assertions.assertEquals(header, originalHeader.get());
+        }
+    }
+
+    @Test
+    void testNullHeader() {
+        final AtomicReference<String> originalHeader = new AtomicReference<>();
+        RuntimeDelegate.setInstance(new StringHeaderRuntimeDelegate(RuntimeDelegate.getInstance()));
+        try (Response response = ClientBuilder.newClient().register(new ClientRequestFilter() {
+                    @Override
+                    public void filter(ClientRequestContext requestContext) throws IOException {
+                        requestContext.abortWith(Response.ok()
+                                .header(header, new StringHeader())
+                                .entity(entity).build());
+                    }
+                }).register(new ClientResponseFilter() {
+                    @Override
+                    public void filter(ClientRequestContext requestContext, ClientResponseContext responseContext)
+                            throws IOException {
+                        originalHeader.set(responseContext.getHeaderString(header));
+                    }
+                })
+                .target("http://localhost:8080").request().get()) {
+            Assertions.assertEquals(entity, response.readEntity(String.class));
+            Assertions.assertEquals("", originalHeader.get());
+        }
+    }
+
+    private static class StringHeader extends AtomicReference<String> {
+
+    }
+
+    private static class StringHeaderDelegate implements RuntimeDelegate.HeaderDelegate<StringHeader> {
+        @Override
+        public StringHeader fromString(String value) {
+            StringHeader stringHeader = new StringHeader();
+            stringHeader.set(value);
+            return stringHeader;
+        }
+
+        @Override
+        public String toString(StringHeader value) {
+            //on purpose
+            return null;
+        }
+    }
+
+    private static class StringHeaderRuntimeDelegate extends RuntimeDelegate {
+        private final RuntimeDelegate original;
+
+        private StringHeaderRuntimeDelegate(RuntimeDelegate original) {
+            this.original = original;
+        }
+
+        @Override
+        public UriBuilder createUriBuilder() {
+            return original.createUriBuilder();
+        }
+
+        @Override
+        public Response.ResponseBuilder createResponseBuilder() {
+            return original.createResponseBuilder();
+        }
+
+        @Override
+        public Variant.VariantListBuilder createVariantListBuilder() {
+            return original.createVariantListBuilder();
+        }
+
+        @Override
+        public <T> T createEndpoint(Application application, Class<T> endpointType)
+                throws IllegalArgumentException, UnsupportedOperationException {
+            return original.createEndpoint(application, endpointType);
+        }
+
+        @Override
+        @SuppressWarnings("unchecked")
+        public <T> HeaderDelegate<T> createHeaderDelegate(Class<T> type) throws IllegalArgumentException {
+            if (StringHeader.class.equals(type)) {
+                return (HeaderDelegate<T>) new StringHeaderDelegate();
+            }
+            return original.createHeaderDelegate(type);
+        }
+
+        @Override
+        public Link.Builder createLinkBuilder() {
+            return original.createLinkBuilder();
+        }
+
+        @Override
+        public SeBootstrap.Configuration.Builder createConfigurationBuilder() {
+            return original.createConfigurationBuilder();
+        }
+
+        @Override
+        public CompletionStage<SeBootstrap.Instance> bootstrap(Application application, SeBootstrap.Configuration configuration) {
+            return original.bootstrap(application, configuration);
+        }
+
+        @Override
+        public CompletionStage<SeBootstrap.Instance> bootstrap(Class<? extends Application> clazz,
+                                                               SeBootstrap.Configuration configuration) {
+            return original.bootstrap(clazz, configuration);
+        }
+
+        @Override
+        public EntityPart.Builder createEntityPartBuilder(String partName) throws IllegalArgumentException {
+            return original.createEntityPartBuilder(partName);
+        }
+    }
+
+}
diff --git a/core-client/src/test/java/org/glassfish/jersey/client/authentication/BasicAuthenticatorTest.java b/core-client/src/test/java/org/glassfish/jersey/client/authentication/BasicAuthenticatorTest.java
new file mode 100644
index 0000000..ad5b721
--- /dev/null
+++ b/core-client/src/test/java/org/glassfish/jersey/client/authentication/BasicAuthenticatorTest.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 2025 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package org.glassfish.jersey.client.authentication;
+
+import org.junit.jupiter.api.Test;
+
+import jakarta.ws.rs.client.ClientRequestContext;
+import jakarta.ws.rs.client.ClientResponseContext;
+import jakarta.ws.rs.core.HttpHeaders;
+import jakarta.ws.rs.core.MultivaluedMap;
+import java.util.Arrays;
+import java.util.Collections;
+
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+class BasicAuthenticatorTest {
+
+    @Test
+    void filterResponseAndAuthenticateNoAuthHeadersTest() {
+        final BasicAuthenticator authenticator
+                = new BasicAuthenticator(new HttpAuthenticationFilter.Credentials("foo", "bar"));
+        final ClientRequestContext request = mock(ClientRequestContext.class);
+        final ClientResponseContext response = mock(ClientResponseContext.class);
+
+        when(response.getHeaders()).thenReturn(mock(MultivaluedMap.class));
+
+        assertFalse(authenticator.filterResponseAndAuthenticate(request, response));
+    }
+
+    @Test
+    void filterResponseAndAuthenticateAuthHeaderNotBasicTest() {
+        final BasicAuthenticator authenticator
+                = new BasicAuthenticator(new HttpAuthenticationFilter.Credentials("foo", "bar"));
+        final ClientRequestContext request = mock(ClientRequestContext.class);
+        final ClientResponseContext response = mock(ClientResponseContext.class);
+
+        final MultivaluedMap<String, String> headers = mock(MultivaluedMap.class);
+        when(response.getHeaders()).thenReturn(headers);
+        when(headers.get(HttpHeaders.WWW_AUTHENTICATE)).thenReturn(Collections.singletonList("Digest realm=\"test\""));
+
+        assertFalse(authenticator.filterResponseAndAuthenticate(request, response));
+    }
+
+    @Test
+    void filterResponseAndAuthenticateEmptyListTest() {
+        final BasicAuthenticator authenticator
+                = new BasicAuthenticator(new HttpAuthenticationFilter.Credentials("foo", "bar"));
+        final ClientRequestContext request = mock(ClientRequestContext.class);
+        final ClientResponseContext response = mock(ClientResponseContext.class);
+
+        final MultivaluedMap<String, String> headers = mock(MultivaluedMap.class);
+        when(response.getHeaders()).thenReturn(headers);
+        when(headers.get(HttpHeaders.WWW_AUTHENTICATE)).thenReturn(Collections.emptyList());
+
+        assertFalse(authenticator.filterResponseAndAuthenticate(request, response));
+    }
+
+    @Test
+    void filterResponseAndAuthenticateNullListTest() {
+        final BasicAuthenticator authenticator
+                = new BasicAuthenticator(new HttpAuthenticationFilter.Credentials("foo", "bar"));
+        final ClientRequestContext request = mock(ClientRequestContext.class);
+        final ClientResponseContext response = mock(ClientResponseContext.class);
+
+        final MultivaluedMap<String, String> headers = mock(MultivaluedMap.class);
+        when(response.getHeaders()).thenReturn(headers);
+        when(headers.get(HttpHeaders.WWW_AUTHENTICATE)).thenReturn(null);
+
+        assertFalse(authenticator.filterResponseAndAuthenticate(request, response));
+    }
+
+    @Test
+    void filterResponseAndAuthenticateMissingCredentialsMultipleAuthRealmsTest() {
+        final String[] authHeaders = new String[] {
+                "Digest realm=\"test\"",
+                "Basic realm=\"test\""
+        };
+        final BasicAuthenticator authenticator = new BasicAuthenticator(null);
+        final ClientRequestContext request = mock(ClientRequestContext.class);
+        final ClientResponseContext response = mock(ClientResponseContext.class);
+
+        final MultivaluedMap<String, String> headers = mock(MultivaluedMap.class);
+        when(response.getHeaders()).thenReturn(headers);
+        when(headers.get(HttpHeaders.WWW_AUTHENTICATE)).thenReturn(Arrays.asList(authHeaders));
+        when(response.hasEntity()).thenReturn(false);
+
+        assertThrows(ResponseAuthenticationException.class,
+                () -> authenticator.filterResponseAndAuthenticate(request, response));
+    }
+
+}
diff --git a/core-client/src/test/java/org/glassfish/jersey/client/innate/http/SSLParamConfiguratorTest.java b/core-client/src/test/java/org/glassfish/jersey/client/innate/http/SSLParamConfiguratorTest.java
index 06dcdec..e7a61d0 100644
--- a/core-client/src/test/java/org/glassfish/jersey/client/innate/http/SSLParamConfiguratorTest.java
+++ b/core-client/src/test/java/org/glassfish/jersey/client/innate/http/SSLParamConfiguratorTest.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2024 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2024, 2025 Oracle and/or its affiliates. All rights reserved.
  *
  * This program and the accompanying materials are made available under the
  * terms of the Eclipse Public License v. 2.0, which is available at
@@ -27,9 +27,13 @@
 import org.hamcrest.Matchers;
 import org.junit.jupiter.api.Test;
 
+import jakarta.ws.rs.ProcessingException;
+import jakarta.ws.rs.client.Client;
 import jakarta.ws.rs.client.ClientBuilder;
 import jakarta.ws.rs.core.MultivaluedHashMap;
+import jakarta.ws.rs.core.Response;
 
+import java.net.ConnectException;
 import java.net.URI;
 import java.util.Collections;
 import java.util.List;
@@ -155,4 +159,56 @@
         MatcherAssert.assertThat(configurator.isSNIRequired(), Matchers.is(true));
         MatcherAssert.assertThat(configurator.getSNIHostName(), Matchers.is("yyy.com"));
     }
+
+    @Test
+    public void testIPv6Header() {
+        final String HOST_HEADER_IPv6 = "[172:30::333b]";
+        final URI uri = URI.create("http://[172:30::333a]:8080/api/demo/v1");
+        final JerseyClient client = (JerseyClient) ClientBuilder.newClient();
+        Map<String, List<Object>> httpHeaders = new MultivaluedHashMap<>();
+        httpHeaders.put(HttpHeaders.HOST, Collections.singletonList(HOST_HEADER_IPv6 + ":8080"));
+        SSLParamConfigurator configurator = SSLParamConfigurator.builder()
+                .uri(uri)
+                .headers(httpHeaders)
+                .configuration(client.getConfiguration())
+                .build();
+        MatcherAssert.assertThat(configurator.isSNIRequired(), Matchers.is(true));
+        MatcherAssert.assertThat(configurator.getSNIHostName(), Matchers.is(HOST_HEADER_IPv6));
+        URI expected = URI.create("http://" + HOST_HEADER_IPv6 + ":8080/api/demo/v1");
+        MatcherAssert.assertThat(configurator.getSNIUri(), Matchers.is(expected));
+        MatcherAssert.assertThat(configurator.toIPRequestUri().toString(),
+                Matchers.is(uri.toString().replace("::", ":0:0:0:0:0:")));
+    }
+
+    @Test
+    public void testIpv6Request() {
+        Client client = ClientBuilder.newClient();
+        String u = "http://[::1]:8080";
+        try {
+            client.target(u)
+                    .request()
+                    .header(HttpHeaders.HOST, "[172:30::333b]:8080")
+                    .get();
+        } catch (ProcessingException pe) {
+            if (!ConnectException.class.isInstance(pe.getCause())) {
+                throw pe;
+            }
+        }
+    }
+
+    @Test
+    public void testIpv6RequestNoPort() {
+        Client client = ClientBuilder.newClient();
+        String u = "http://[::1]";
+        try {
+            client.target(u)
+                    .request()
+                    .header(HttpHeaders.HOST, "[172:30::333b]")
+                    .get();
+        } catch (ProcessingException pe) {
+            if (!ConnectException.class.isInstance(pe.getCause())) {
+                throw pe;
+            }
+        }
+    }
 }
diff --git a/core-common/src/main/java/org/glassfish/jersey/internal/util/collection/Views.java b/core-common/src/main/java/org/glassfish/jersey/internal/util/collection/Views.java
index 4765056..75b1987 100644
--- a/core-common/src/main/java/org/glassfish/jersey/internal/util/collection/Views.java
+++ b/core-common/src/main/java/org/glassfish/jersey/internal/util/collection/Views.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, 2024 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2025 Oracle and/or its affiliates. All rights reserved.
  *
  * This program and the accompanying materials are made available under the
  * terms of the Eclipse Public License v. 2.0, which is available at
@@ -129,60 +129,107 @@
      * @return transformed map view.
      */
     public static <K, V, O> Map<K, V> mapView(Map<K, O> originalMap, Function<O, V> valuesTransformer) {
-        return new AbstractMap<K, V>() {
-            @Override
-            public Set<Entry<K, V>> entrySet() {
-                return new AbstractSet<Entry<K, V>>() {
+        return new KVOMap<K, V, O>(originalMap, valuesTransformer);
+    }
 
+    private static class KVOMap<K, V, O> extends AbstractMap<K, V> {
+            protected final Map<K, O> originalMap;
+            protected final Function<O, V> valuesTransformer;
 
-                    Set<Entry<K, O>> originalSet = originalMap.entrySet();
-                    Iterator<Entry<K, O>> original = originalSet.iterator();
+        private KVOMap(Map<K, O> originalMap, Function<O, V> valuesTransformer) {
+            this.originalMap = originalMap;
+            this.valuesTransformer = valuesTransformer;
+        }
 
-                    @Override
-                    public Iterator<Entry<K, V>> iterator() {
-                        return new Iterator<Entry<K, V>>() {
-                            @Override
-                            public boolean hasNext() {
-                                return original.hasNext();
-                            }
+        @Override
+        public Set<Entry<K, V>> entrySet() {
+            return new AbstractSet<Entry<K, V>>() {
 
-                            @Override
-                            public Entry<K, V> next() {
+                Set<Entry<K, O>> originalSet = originalMap.entrySet();
+                Iterator<Entry<K, O>> original = originalSet.iterator();
 
-                                Entry<K, O> next = original.next();
+                @Override
+                public Iterator<Entry<K, V>> iterator() {
+                    return new Iterator<Entry<K, V>>() {
+                        @Override
+                        public boolean hasNext() {
+                            return original.hasNext();
+                        }
 
-                                return new Entry<K, V>() {
-                                    @Override
-                                    public K getKey() {
-                                        return next.getKey();
-                                    }
+                        @Override
+                        public Entry<K, V> next() {
 
-                                    @Override
-                                    public V getValue() {
-                                        return valuesTransformer.apply(next.getValue());
-                                    }
+                            Entry<K, O> next = original.next();
 
-                                    @Override
-                                    public V setValue(V value) {
-                                        throw new UnsupportedOperationException("Not supported.");
-                                    }
-                                };
-                            }
+                            return new Entry<K, V>() {
+                                @Override
+                                public K getKey() {
+                                    return next.getKey();
+                                }
 
-                            @Override
-                            public void remove() {
-                                original.remove();
-                            }
-                        };
-                    }
+                                @Override
+                                public V getValue() {
+                                    return valuesTransformer.apply(next.getValue());
+                                }
 
-                    @Override
-                    public int size() {
-                        return originalSet.size();
-                    }
-                };
-            }
-        };
+                                @Override
+                                public V setValue(V value) {
+                                    return KVOMap.this.setValue(next, value);
+                                }
+                            };
+                        }
+
+                        @Override
+                        public void remove() {
+                            original.remove();
+                        }
+                    };
+                }
+
+                @Override
+                public int size() {
+                    return originalSet.size();
+                }
+            };
+        }
+
+        protected V setValue(Map.Entry<K, O> entry, V value) {
+            throw new UnsupportedOperationException("Not supported.");
+        }
+    }
+
+    /**
+     * Create a {@link Map} view, which transforms the values of provided original map.
+     * <p>
+     *
+     * @param originalMap       provided map.
+     * @param valuesTransformer values transformer.
+     * @return transformed map view.
+     */
+    public static Map<String, List<String>> mapObjectToStringView(Map<String, List<Object>> originalMap,
+                                                            Function<List<Object>, List<String>> valuesTransformer) {
+        return new ObjectToStringMap(originalMap, valuesTransformer);
+    }
+
+    private static class ObjectToStringMap extends KVOMap<String, List<String>, List<Object>> {
+
+        private ObjectToStringMap(Map<String, List<Object>> originalMap, Function<List<Object>, List<String>> valuesTransformer) {
+            super(originalMap, valuesTransformer);
+        }
+
+        @Override
+        protected List<String> setValue(Entry<String, List<Object>> entry, List<String> value) {
+            @SuppressWarnings("unchecked")
+            final List<Object> old = entry.setValue((List<Object>) (List<?>) value);
+            return valuesTransformer.apply(old);
+        }
+
+        @Override
+        public List<String> put(String key, List<String> value) {
+            @SuppressWarnings("unchecked")
+            final List<Object> old = originalMap.put(key, (List<Object>) (List<?>) value);
+            return valuesTransformer.apply(old);
+        }
     }
 
     /**
diff --git a/core-common/src/main/java/org/glassfish/jersey/message/internal/CookiesParser.java b/core-common/src/main/java/org/glassfish/jersey/message/internal/CookiesParser.java
index 14a008d..958a1bc 100644
--- a/core-common/src/main/java/org/glassfish/jersey/message/internal/CookiesParser.java
+++ b/core-common/src/main/java/org/glassfish/jersey/message/internal/CookiesParser.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010, 2024 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2010, 2025 Oracle and/or its affiliates. All rights reserved.
  *
  * This program and the accompanying materials are made available under the
  * terms of the Eclipse Public License v. 2.0, which is available at
@@ -86,20 +86,29 @@
     }
 
     /**
-     * Check if a cookie with identical name had been parsed.
-     * If yes, the one with the longest string will be kept
+     * Check if a cookie with similar names had been parsed.
+     * If yes, the one with the longest path will be kept
+     * For similar paths the newest is stored
      * @param cookies : Map of cookies
      * @param cookie : Cookie to be checked
      */
     private static void checkSimilarCookieName(Map<String, Cookie> cookies, MutableCookie cookie) {
-        if (cookie != null) {
-            if (cookies.containsKey(cookie.name)){
-                if (cookie.value.length() > cookies.get(cookie.name).getValue().length()){
-                    cookies.put(cookie.name, cookie.getImmutableCookie());
-                }
-            } else {
-                cookies.put(cookie.name, cookie.getImmutableCookie());
-            }
+        if (cookie == null) {
+            return;
+        }
+
+        boolean alreadyPresent = cookies.containsKey(cookie.name);
+        boolean recordCookie = !alreadyPresent;
+
+        if (alreadyPresent) {
+            final String newPath = cookie.path == null ? "" : cookie.path;
+            final String existingPath = cookies.get(cookie.name).getPath() == null ? ""
+                    : cookies.get(cookie.name).getPath();
+            recordCookie = (newPath.length() >= existingPath.length());
+        }
+
+        if (recordCookie) {
+            cookies.put(cookie.name, cookie.getImmutableCookie());
         }
     }
 
diff --git a/core-common/src/main/java/org/glassfish/jersey/message/internal/HeaderUtils.java b/core-common/src/main/java/org/glassfish/jersey/message/internal/HeaderUtils.java
index aeea686..c60386b 100644
--- a/core-common/src/main/java/org/glassfish/jersey/message/internal/HeaderUtils.java
+++ b/core-common/src/main/java/org/glassfish/jersey/message/internal/HeaderUtils.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010, 2022 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2010, 2025 Oracle and/or its affiliates. All rights reserved.
  *
  * This program and the accompanying materials are made available under the
  * terms of the Eclipse Public License v. 2.0, which is available at
@@ -210,7 +210,7 @@
         }
 
         return new AbstractMultivaluedMap<String, String>(
-                Views.mapView(headers, input -> HeaderUtils.asStringList(input, rd))
+                Views.mapObjectToStringView(headers, input -> HeaderUtils.asStringList(input, rd))
         ) {
         };
     }
diff --git a/core-common/src/main/java/org/glassfish/jersey/message/internal/InboundMessageContext.java b/core-common/src/main/java/org/glassfish/jersey/message/internal/InboundMessageContext.java
index 29cb6e0..46446a4 100644
--- a/core-common/src/main/java/org/glassfish/jersey/message/internal/InboundMessageContext.java
+++ b/core-common/src/main/java/org/glassfish/jersey/message/internal/InboundMessageContext.java
@@ -157,8 +157,22 @@
      *                      as required by JAX-RS specification on the server side.
      */
     public InboundMessageContext(Configuration configuration, boolean translateNce) {
+        this(configuration, HeaderUtils.createInbound(), translateNce);
+    }
+
+    /**
+     * Create new inbound message context.
+     *
+     * @param configuration the related client/server side {@link Configuration}. If {@code null},
+     *                      the default behaviour is expected.
+     * @param httpHeaders   the http headers map.
+     * @param translateNce  if {@code true}, the {@link javax.ws.rs.core.NoContentException} thrown by a
+     *                      selected message body reader will be translated into a {@link javax.ws.rs.BadRequestException}
+     *                      as required by JAX-RS specification on the server side.
+     */
+    public InboundMessageContext(Configuration configuration, MultivaluedMap<String, String> httpHeaders, boolean translateNce) {
         super(configuration);
-        this.headers = new GuardianStringKeyMultivaluedMap<>(HeaderUtils.createInbound());
+        this.headers = new GuardianStringKeyMultivaluedMap<>(httpHeaders);
         this.entityContent = new EntityContent();
         this.translateNce = translateNce;
         this.configuration = configuration;
@@ -302,7 +316,11 @@
         }
 
         final Iterator<String> valuesIterator = values.iterator();
-        StringBuilder buffer = new StringBuilder(valuesIterator.next());
+        String next = valuesIterator.next();
+        if (next == null) {
+            next = "";
+        }
+        StringBuilder buffer = new StringBuilder(next);
         while (valuesIterator.hasNext()) {
             buffer.append(',').append(valuesIterator.next());
         }
diff --git a/core-common/src/main/java/org/glassfish/jersey/message/internal/OutboundMessageContext.java b/core-common/src/main/java/org/glassfish/jersey/message/internal/OutboundMessageContext.java
index efa8899..953c27f 100644
--- a/core-common/src/main/java/org/glassfish/jersey/message/internal/OutboundMessageContext.java
+++ b/core-common/src/main/java/org/glassfish/jersey/message/internal/OutboundMessageContext.java
@@ -134,7 +134,7 @@
      */
     @Deprecated
     public OutboundMessageContext() {
-        this ((Configuration) null);
+        this((Configuration) null);
     }
 
     /**
diff --git a/core-common/src/main/java/org/glassfish/jersey/message/internal/ReaderWriter.java b/core-common/src/main/java/org/glassfish/jersey/message/internal/ReaderWriter.java
index ae8e7d8..dd0fc8e 100644
--- a/core-common/src/main/java/org/glassfish/jersey/message/internal/ReaderWriter.java
+++ b/core-common/src/main/java/org/glassfish/jersey/message/internal/ReaderWriter.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010, 2023 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2010, 2025 Oracle and/or its affiliates. All rights reserved.
  *
  * This program and the accompanying materials are made available under the
  * terms of the Eclipse Public License v. 2.0, which is available at
@@ -184,11 +184,23 @@
         }
         return sb.toString();
     }
+
     /**
-     * The maximum size of array to allocate.
+     * Read/convert stream to the byte array.
+     *
+     * @param in stream to be converted to the byte array
+     * @return the byte array
+     * @throws IOException if there is an error reading from the stream
+     * @since 2.47
+     */
+    public static byte[] readFromAsBytes(InputStream in) throws IOException {
+        return readAllBytes(in);
+    }
+    /**
+     * The maximum size of an array to allocate.
      * Some VMs reserve some header words in an array.
      * Attempts to allocate larger arrays may result in
-     * OutOfMemoryError: Requested array size exceeds VM limit
+     * OutOfMemoryError: Requested array size exceeds the VM limit
      */
     private static final int MAX_BUFFER_SIZE = Integer.MAX_VALUE - 8;
 
diff --git a/core-server/src/main/java/jersey/repackaged/org/objectweb/asm/ClassReader.java b/core-server/src/main/java/jersey/repackaged/org/objectweb/asm/ClassReader.java
index f5d846a..e027bdc 100644
--- a/core-server/src/main/java/jersey/repackaged/org/objectweb/asm/ClassReader.java
+++ b/core-server/src/main/java/jersey/repackaged/org/objectweb/asm/ClassReader.java
@@ -195,7 +195,7 @@
     this.b = classFileBuffer;
     // Check the class' major_version. This field is after the magic and minor_version fields, which
     // use 4 and 2 bytes respectively.
-    if (checkClassVersion && readShort(classFileOffset + 6) > Opcodes.V24) {
+    if (checkClassVersion && readShort(classFileOffset + 6) > Opcodes.V25) {
       throw new IllegalArgumentException(
           "Unsupported class file major version " + readShort(classFileOffset + 6));
     }
diff --git a/core-server/src/main/java/jersey/repackaged/org/objectweb/asm/MethodVisitor.java b/core-server/src/main/java/jersey/repackaged/org/objectweb/asm/MethodVisitor.java
index e2f2c92..29eac8f 100644
--- a/core-server/src/main/java/jersey/repackaged/org/objectweb/asm/MethodVisitor.java
+++ b/core-server/src/main/java/jersey/repackaged/org/objectweb/asm/MethodVisitor.java
@@ -596,7 +596,7 @@
    * Visits a LOOKUPSWITCH instruction.
    *
    * @param dflt beginning of the default handler block.
-   * @param keys the values of the keys.
+   * @param keys the values of the keys. Keys must be sorted in increasing order.
    * @param labels beginnings of the handler blocks. {@code labels[i]} is the beginning of the
    *     handler block for the {@code keys[i]} key.
    */
diff --git a/core-server/src/main/java/jersey/repackaged/org/objectweb/asm/Opcodes.java b/core-server/src/main/java/jersey/repackaged/org/objectweb/asm/Opcodes.java
index eeb3df7..8a6ca40 100644
--- a/core-server/src/main/java/jersey/repackaged/org/objectweb/asm/Opcodes.java
+++ b/core-server/src/main/java/jersey/repackaged/org/objectweb/asm/Opcodes.java
@@ -290,6 +290,7 @@
   int V22 = 0 << 16 | 66;
   int V23 = 0 << 16 | 67;
   int V24 = 0 << 16 | 68;
+  int V25 = 0 << 16 | 69;
 
   /**
    * Version flag indicating that the class is using 'preview' features.
diff --git a/core-server/src/main/java/org/glassfish/jersey/server/internal/scanning/AnnotationAcceptingListener.java b/core-server/src/main/java/org/glassfish/jersey/server/internal/scanning/AnnotationAcceptingListener.java
index 917d094..807252c 100644
--- a/core-server/src/main/java/org/glassfish/jersey/server/internal/scanning/AnnotationAcceptingListener.java
+++ b/core-server/src/main/java/org/glassfish/jersey/server/internal/scanning/AnnotationAcceptingListener.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2024 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2025 Oracle and/or its affiliates. All rights reserved.
  *
  * This program and the accompanying materials are made available under the
  * terms of the Eclipse Public License v. 2.0, which is available at
@@ -309,7 +309,7 @@
 
     private static class ClassReaderWrapper {
         private static final Logger LOGGER = Logger.getLogger(ClassReader.class.getName());
-        private static final int WARN_VERSION = Opcodes.V24;
+        private static final int WARN_VERSION = Opcodes.V25;
         private static final int INPUT_STREAM_DATA_CHUNK_SIZE = 4096;
 
         private final byte[] b;
diff --git a/core-server/src/main/resources/META-INF/NOTICE.markdown b/core-server/src/main/resources/META-INF/NOTICE.markdown
index 2016cb4..ab6fea0 100644
--- a/core-server/src/main/resources/META-INF/NOTICE.markdown
+++ b/core-server/src/main/resources/META-INF/NOTICE.markdown
@@ -36,7 +36,7 @@
 * Copyright (c) 2015-2018 Oracle and/or its affiliates. All rights reserved.

 * Copyright 2010-2013 Coda Hale and Yammer, Inc.

 

-org.objectweb.asm Version 9.7.1

+org.objectweb.asm Version 9.8

 * License: Modified BSD (https://asm.ow2.io/license.html)

 * Copyright: (c) 2000-2011 INRIA, France Telecom. All rights reserved.

 

diff --git a/examples/NOTICE.md b/examples/NOTICE.md
index ed616c2..d1be3d9 100644
--- a/examples/NOTICE.md
+++ b/examples/NOTICE.md
@@ -96,7 +96,7 @@
 * Project: http://www.kineticjs.com, https://github.com/ericdrowell/KineticJS
 * Copyright: Eric Rowell
 
-org.objectweb.asm Version 9.7.1
+org.objectweb.asm Version 9.8
 * License: Modified BSD (https://asm.ow2.io/license.html)
 * Copyright (c) 2000-2011 INRIA, France Telecom. All rights reserved.
 
diff --git a/examples/expect-100-continue-netty-client/README.MD b/examples/expect-100-continue-netty-client/README.MD
new file mode 100644
index 0000000..5749184
--- /dev/null
+++ b/examples/expect-100-continue-netty-client/README.MD
@@ -0,0 +1,62 @@
+[//]: # " Copyright (c) 2025 Oracle and/or its affiliates. All rights reserved. "
+[//]: # " "
+[//]: # " This program and the accompanying materials are made available under the "
+[//]: # " terms of the Eclipse Distribution License v. 1.0, which is available at "
+[//]: # " http://www.eclipse.org/org/documents/edl-v10.php. "
+[//]: # " "
+[//]: # " SPDX-License-Identifier: BSD-3-Clause "
+
+jersey-example-expect-100-continue-netty-connector
+==========================================================
+
+This example demonstrates how to register and run Jersey Netty connector with Expect:100-continue feature on.
+It also provides custom low-level Socket server to demonstrate how is request is captured and processed.  
+
+Contents
+--------
+
+The server and client are operating on requests level, without exposing any Resources. Client only sends request in
+form 
+```json
+{"message":"Hello from java client"}
+```
+
+Sample Response
+---------------
+Server in turn shows output which demonstrates Expect:100-continue presence and handling
+
+```shell
+==== DUMPING HEADERS ====
+expect, 100-continue
+transfer-encoding, chunked
+host, 127.0.0.1:3000
+content-type, application/json
+accept, application/json
+user-agent, jersey/2.47-snapshot (netty 4.1.112.final)
+==== HEADERS DUMPED =====
+==== DUMPING RESPONSE ====
+HTTP/1.1 100 Continue
+Connection: keep-alive
+
+
+==== RESPONSE DUMPED =====
+24
+{"message":"Hello from java client"}
+==== DUMPING RESPONSE ====
+HTTP/1.1 204 No Content
+Server: Socket Server v.0.0.1
+
+
+```
+
+Running the Example
+-------------------
+
+Run the example using provided ServerSocket container as follows:
+
+>     mvn clean compile exec:java
+
+Run the example using client as follows:
+
+>     mvn clean package exec:java -Pclient
+
diff --git a/examples/expect-100-continue-netty-client/pom.xml b/examples/expect-100-continue-netty-client/pom.xml
new file mode 100644
index 0000000..287a9b6
--- /dev/null
+++ b/examples/expect-100-continue-netty-client/pom.xml
@@ -0,0 +1,91 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+    Copyright (c) 2025 Oracle and/or its affiliates. All rights reserved.
+
+    This program and the accompanying materials are made available under the
+    terms of the Eclipse Distribution License v. 1.0, which is available at
+    http://www.eclipse.org/org/documents/edl-v10.php.
+
+    SPDX-License-Identifier: BSD-3-Clause
+
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.glassfish.jersey.examples</groupId>
+        <artifactId>project</artifactId>
+        <version>3.1.99-SNAPSHOT</version>
+    </parent>
+
+
+
+    <artifactId>jersey-example-expect-100-continue-netty-client</artifactId>
+    <packaging>jar</packaging>
+    <name>jersey-example-expect-100-continue-netty-client</name>
+
+    <description>Jersey example for Expect: 100-continue header usage with netty connector.</description>
+
+    <dependencies>
+
+        <dependency>
+            <groupId>org.glassfish.jersey.connectors</groupId>
+            <artifactId>jersey-netty-connector</artifactId>
+        </dependency>
+
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.codehaus.mojo</groupId>
+                <artifactId>exec-maven-plugin</artifactId>
+                <configuration>
+                    <mainClass>${mainClass}</mainClass>
+                </configuration>
+            </plugin>
+
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-compiler-plugin</artifactId>
+                <inherited>true</inherited>
+                <configuration>
+                    <showWarnings>false</showWarnings>
+                    <fork>false</fork>
+                </configuration>
+            </plugin>
+
+            <!-- Run the application using "mvn jetty:run" -->
+
+        </plugins>
+    </build>
+
+    <profiles>
+        <profile>
+            <id>client</id>
+            <properties>
+                <mainClass>org.glassfish.jersey.examples.expect100continue.netty.connector.NettyClient</mainClass>
+            </properties>
+        </profile>
+        <profile>
+            <id>pre-release</id>
+            <build>
+                <plugins>
+                    <plugin>
+                        <groupId>org.codehaus.mojo</groupId>
+                        <artifactId>xml-maven-plugin</artifactId>
+                    </plugin>
+                    <plugin>
+                        <groupId>org.apache.maven.plugins</groupId>
+                        <artifactId>maven-assembly-plugin</artifactId>
+                    </plugin>
+                </plugins>
+            </build>
+        </profile>
+    </profiles>
+
+    <properties>
+        <mainClass>org.glassfish.jersey.examples.expect100continue.netty.connector.SocketServer</mainClass>
+    </properties>
+</project>
diff --git a/examples/expect-100-continue-netty-client/src/main/java/org/glassfish/jersey/examples/expect100continue/netty/connector/NettyClient.java b/examples/expect-100-continue-netty-client/src/main/java/org/glassfish/jersey/examples/expect100continue/netty/connector/NettyClient.java
new file mode 100644
index 0000000..fa27674
--- /dev/null
+++ b/examples/expect-100-continue-netty-client/src/main/java/org/glassfish/jersey/examples/expect100continue/netty/connector/NettyClient.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2025 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0, which is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+package org.glassfish.jersey.examples.expect100continue.netty.connector;
+
+import org.glassfish.jersey.client.ClientConfig;
+import org.glassfish.jersey.client.ClientProperties;
+import org.glassfish.jersey.client.RequestEntityProcessing;
+import org.glassfish.jersey.client.http.Expect100ContinueFeature;
+import org.glassfish.jersey.logging.LoggingFeature;
+import org.glassfish.jersey.netty.connector.NettyConnectorProvider;
+
+import jakarta.ws.rs.client.Client;
+import jakarta.ws.rs.client.ClientBuilder;
+import jakarta.ws.rs.client.Entity;
+import jakarta.ws.rs.client.Invocation;
+import jakarta.ws.rs.client.WebTarget;
+import jakarta.ws.rs.core.MediaType;
+import jakarta.ws.rs.core.Response;
+import java.util.logging.Handler;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+public class NettyClient {
+    public static void main(String[] args) throws InterruptedException {
+//        enableLogging(Level.FINE);
+        test();
+    }
+
+    public static void test() throws InterruptedException {
+        ClientConfig defaultConfig = new ClientConfig();
+        defaultConfig.property(LoggingFeature.LOGGING_FEATURE_VERBOSITY_CLIENT, LoggingFeature.Verbosity.PAYLOAD_ANY);
+
+        //The issue can be produced only by using NettyConnectorProvider
+        defaultConfig.connectorProvider(new NettyConnectorProvider());
+
+        //with below two lines, enabled 100-continue feature
+        defaultConfig.property(ClientProperties.REQUEST_ENTITY_PROCESSING, RequestEntityProcessing.CHUNKED);
+        defaultConfig.register(Expect100ContinueFeature.basic());
+
+        Client client = ClientBuilder.newClient(defaultConfig);
+        WebTarget webTarget = client.target("http://127.0.0.1:3000");
+        Invocation.Builder invocationBuilder = webTarget.request();
+        invocationBuilder.header("Accept", "application/json");
+
+        for (int i = 0; i < 5; i++) { //iterating few times here to demonstrate
+            // the 100-continue processing works on any iteration
+
+            System.out.println();
+            System.out.println("****************** Iteration #" + i + " ******************");
+
+            final Response response = invocationBuilder.post(generateSimpleEntity());
+
+            System.out.println("Response status = " + response.getStatus());
+            System.out.println("Response status 204 means No Content, so we do not expect body here");
+            System.out.println("**************************************************");
+            System.out.println();
+        }
+        System.out.println("Client connection should be closed manually with Ctrl-C");
+    }
+
+    private static Entity<String> generateSimpleEntity(){
+        return Entity.entity("{\"message\":\"Hello from java client\"}", MediaType.APPLICATION_JSON_TYPE);
+    }
+
+    private static void enableLogging(Level logLevel) {
+        Logger rootLogger = Logger.getLogger("");
+        rootLogger.setLevel(logLevel);
+        Logger nettyLog = Logger.getLogger("io.netty");
+        nettyLog.setLevel(logLevel);
+        Handler[] handlers = rootLogger.getHandlers();
+        for (final Handler handler : handlers) {
+            handler.setLevel(logLevel);
+        }
+    }
+}
diff --git a/examples/expect-100-continue-netty-client/src/main/java/org/glassfish/jersey/examples/expect100continue/netty/connector/SocketServer.java b/examples/expect-100-continue-netty-client/src/main/java/org/glassfish/jersey/examples/expect100continue/netty/connector/SocketServer.java
new file mode 100644
index 0000000..6fd5699
--- /dev/null
+++ b/examples/expect-100-continue-netty-client/src/main/java/org/glassfish/jersey/examples/expect100continue/netty/connector/SocketServer.java
@@ -0,0 +1,255 @@
+/*
+ * Copyright (c) 2025 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0, which is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+package org.glassfish.jersey.examples.expect100continue.netty.connector;
+
+import javax.net.ServerSocketFactory;
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.OutputStreamWriter;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.util.HashMap;
+import java.util.Locale;
+import java.util.Map;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+public class SocketServer {
+    private static final String NO_CONTENT_HEADER = "HTTP/1.1 204 No Content";
+    private static final String OK_HEADER = "HTTP/1.1 200 OK";
+    private static final String EXPECT_HEADER = "HTTP/1.1 100 Continue";
+    private final ExecutorService executorService = Executors.newCachedThreadPool();
+    private AtomicBoolean expect_processed = new AtomicBoolean(false);
+
+    private ServerSocket server;
+
+    private static final boolean debug = true;
+
+    private static final int port = 3000;
+
+    private volatile boolean stopped = false;
+
+    public static void main(String args[]) throws IOException {
+        new SocketServer(port).runServer();
+    }
+
+    SocketServer(int port) throws IOException {
+        final ServerSocketFactory socketFactory = ServerSocketFactory.getDefault();
+        server = socketFactory.createServerSocket(port);
+    }
+
+    void stop() {
+        stopped = true;
+        try {
+            server.close();
+            executorService.shutdown();
+            while (!executorService.isTerminated()) {
+                executorService.awaitTermination(100, TimeUnit.MILLISECONDS);
+            }
+        } catch (IOException | InterruptedException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    void runServer() {
+
+        executorService.execute(() -> {
+            try {
+                dumpServerReadMe();
+                while (!stopped) {
+                    final Socket socket = server.accept();
+                    executorService.submit(() -> processRequest(socket));
+                }
+            } catch (IOException e) {
+                if (!stopped) {
+                    e.printStackTrace();
+                }
+            }
+        });
+    }
+
+    private void processRequest(final Socket request) {
+
+        try (final BufferedReader reader = new BufferedReader(new InputStreamReader(request.getInputStream()));
+             final BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(request.getOutputStream()))) {
+
+
+            while (!stopped) {
+                final Map<String, String> headers = mapHeaders(reader);
+
+                if (headers.isEmpty()) {
+                    continue;
+                }
+                if (debug) {
+                    dumpHeaders(headers);
+                }
+
+                boolean failed = processExpect100Continue(headers, writer);
+
+                if (failed) {
+                    continue;
+                }
+
+                final String http_header = expect_processed.get() ? NO_CONTENT_HEADER : OK_HEADER;
+                boolean read = readBody(reader, headers);
+
+                final StringBuffer responseBuffer = new StringBuffer(http_header);
+                addNewLineToResponse(responseBuffer);
+                addServerHeaderToResponse(responseBuffer);
+//                    addToResponse("Content-Length: 0", responseBuffer);
+                addNewLineToResponse(responseBuffer);
+                addNewLineToResponse(responseBuffer);
+                if (debug) {
+                    dumpResponse(responseBuffer);
+                }
+
+                writer.write(responseBuffer.toString());
+
+                writer.flush();
+                if (read) {
+                    break;
+                }
+
+            }
+        } catch (Exception e) {
+            e.printStackTrace();
+        } finally {
+            try {
+                request.close();
+            } catch (IOException e) {
+                e.printStackTrace();
+            }
+        }
+    }
+
+    private void addNewLineToResponse(StringBuffer responseBuffer) {
+        addToResponse("\r\n", responseBuffer);
+    }
+
+    private void addToResponse(String toBeAdded, StringBuffer responseBuffer) {
+        responseBuffer.append(toBeAdded);
+    }
+
+    private void addServerHeaderToResponse(StringBuffer responseBuffer) {
+        addToResponse("Server: Example Socket Server v.0.0.1", responseBuffer);
+        addNewLineToResponse(responseBuffer);
+    }
+
+    private boolean processExpect100Continue(Map<String, String> headers, BufferedWriter writer) throws IOException {
+        String http_header = EXPECT_HEADER;
+        boolean failed = false;
+        final String continueHeader = headers.remove("expect");
+
+        if (continueHeader != null && continueHeader.contains("100-continue")) {
+
+            expect_processed.set(http_header.equals(EXPECT_HEADER));
+
+
+            final StringBuffer responseBuffer = new StringBuffer(http_header);
+
+            addNewLineToResponse(responseBuffer);
+            addToResponse("Connection: keep-alive", responseBuffer);
+            addNewLineToResponse(responseBuffer);
+            addNewLineToResponse(responseBuffer);
+            if (debug) {
+                dumpResponse(responseBuffer);
+            }
+
+            writer.write(responseBuffer.toString());
+            writer.flush();
+        }
+        return failed;
+    }
+
+    private Map<String, String> mapHeaders(BufferedReader reader) throws IOException {
+        String line;
+        final Map<String, String> headers = new HashMap<>();
+
+
+        if (!reader.ready()) {
+            return headers;
+        }
+
+        while ((line = reader.readLine()) != null && !line.isEmpty()) {
+
+
+            int pos = line.indexOf(':');
+            if (pos > -1) {
+                headers.put(
+                        line.substring(0, pos).toLowerCase(Locale.ROOT),
+                        line.substring(pos + 2).toLowerCase(Locale.ROOT).trim());
+            }
+        }
+
+        return headers;
+    }
+
+    private boolean readBody(BufferedReader reader, Map<String, String> headers) throws IOException {
+        if (headers.containsKey("content-length")) {
+            int contentLength = Integer.valueOf(headers.get("content-length"));
+            int actualLength = 0, readingByte = 0;
+            int[] buffer = new int[contentLength];
+            while (actualLength < contentLength && (readingByte = reader.read()) != -1) {
+                buffer[actualLength++] = readingByte;
+            }
+            if (debug) {
+                System.out.println("Reading " + actualLength + " of " + contentLength + " bytes/chars");
+            }
+            return (actualLength == contentLength);
+        } else if (headers.containsKey("transfer-encoding")) {
+            String line;
+            while ((line = reader.readLine()) != null && !line.equals("0")) {
+                if (debug) {
+                    System.out.println(line);
+                }
+            }
+            return true;
+        }
+        return false;
+    }
+
+    private void dumpHeaders(Map<String, String> headers) {
+        System.out.println("==== DUMPING HEADERS ====");
+        for (Map.Entry<String, String> entry : headers.entrySet()) {
+            System.out.println(entry.getKey() + ", " + entry.getValue());
+        }
+        System.out.println("==== HEADERS DUMPED =====");
+    }
+
+    private void dumpResponse(StringBuffer responseBuffer) {
+        System.out.println("==== DUMPING RESPONSE ====");
+        System.out.println(responseBuffer);
+        System.out.println("==== RESPONSE DUMPED =====");
+    }
+
+    private void dumpServerReadMe() {
+        System.out.println("==================================Server is running========================================");
+        System.out.println("=                                       ***                                               =");
+        System.out.println("= ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ =");
+        System.out.println("=  You can send requests to it either using Netty Client or curl or any other http tool.  =");
+        System.out.println("=  Try to modify it to see how Expect: 100-continue header works.                         =");
+        System.out.println("= ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ =");
+        System.out.println("=                               stop server by Ctrl-c                                     =");
+        System.out.println("= ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ =");
+        System.out.println("=  Run server using maven:                                                                =");
+        System.out.println("=          mvn clean package exec:java                                                    =");
+        System.out.println("=  Run client using maven:                                                                =");
+        System.out.println("=          mvn clean package exec:java -Pclient                                           =");
+        System.out.println("= ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ =");
+        System.out.println("=                                       ***                                               =");
+        System.out.println("===========================================================================================");
+    }
+
+}
diff --git a/examples/pom.xml b/examples/pom.xml
index 540858b..72695a3 100644
--- a/examples/pom.xml
+++ b/examples/pom.xml
@@ -67,6 +67,7 @@
         <module>entity-filtering-security</module>
         <module>extended-wadl-webapp</module>
         <module>exception-mapping</module>
+        <module>expect-100-continue-netty-client</module>
         <!--<module>feed-combiner-java8-webapp</module>-->
         <module>freemarker-webapp</module>
         <!--<module>flight-mgmt-webapp</module>-->
diff --git a/examples/servlet3-webapp/pom.xml b/examples/servlet3-webapp/pom.xml
index 51b85c2..8693516 100644
--- a/examples/servlet3-webapp/pom.xml
+++ b/examples/servlet3-webapp/pom.xml
@@ -112,15 +112,6 @@
 
     <profiles>
         <profile>
-            <id>jdk8_tests</id>
-            <activation>
-                <jdk>1.8</jdk>
-            </activation>
-            <properties>
-                <junit5.version>${junit5.jdk8.version}</junit5.version>
-            </properties>
-        </profile>
-        <profile>
             <id>pre-release</id>
             <build>
                 <plugins>
diff --git a/inject/hk2/src/main/java/org/glassfish/jersey/inject/hk2/Hk2RequestScope.java b/inject/hk2/src/main/java/org/glassfish/jersey/inject/hk2/Hk2RequestScope.java
index ef96d16..e9437c4 100644
--- a/inject/hk2/src/main/java/org/glassfish/jersey/inject/hk2/Hk2RequestScope.java
+++ b/inject/hk2/src/main/java/org/glassfish/jersey/inject/hk2/Hk2RequestScope.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017, 2021 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2017, 2025 Oracle and/or its affiliates. All rights reserved.
  *
  * This program and the accompanying materials are made available under the
  * terms of the Eclipse Public License v. 2.0, which is available at
@@ -16,8 +16,9 @@
 
 package org.glassfish.jersey.inject.hk2;
 
-import java.util.HashMap;
-import java.util.HashSet;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.LinkedHashMap;
 import java.util.Map;
 import java.util.concurrent.atomic.AtomicInteger;
 import java.util.logging.Level;
@@ -63,7 +64,7 @@
         private final AtomicInteger referenceCounter;
 
         private Instance() {
-            this.store = new HashMap<>();
+            this.store = new LinkedHashMap<>();
             this.referenceCounter = new AtomicInteger(1);
         }
 
@@ -140,7 +141,9 @@
         public void release() {
             if (referenceCounter.decrementAndGet() < 1) {
                 try {
-                    new HashSet<>(store.keySet()).forEach(this::remove);
+                    ArrayList<ForeignDescriptor> reverse = new ArrayList<>(store.keySet());
+                    Collections.reverse(reverse);
+                    reverse.forEach(this::remove);
                 } finally {
                     logger.debugLog("Released scope instance {0}", this);
                 }
diff --git a/media/sse/src/main/java/org/glassfish/jersey/media/sse/internal/EventProcessor.java b/media/sse/src/main/java/org/glassfish/jersey/media/sse/internal/EventProcessor.java
index ee9f56d..8729e4e 100644
--- a/media/sse/src/main/java/org/glassfish/jersey/media/sse/internal/EventProcessor.java
+++ b/media/sse/src/main/java/org/glassfish/jersey/media/sse/internal/EventProcessor.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017, 2024 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2017, 2025 Oracle and/or its affiliates. All rights reserved.
  *
  * This program and the accompanying materials are made available under the
  * terms of the Eclipse Public License v. 2.0, which is available at
@@ -400,7 +400,7 @@
          */
         public Builder reconnectDelay(long reconnectDelay, TimeUnit unit) {
             this.reconnectDelay = reconnectDelay;
-            this.reconnectUnit = reconnectUnit;
+            this.reconnectUnit = unit;
             return this;
         }
 
diff --git a/pom.xml b/pom.xml
index d5a6861..b3ed8d1 100644
--- a/pom.xml
+++ b/pom.xml
@@ -1311,6 +1311,26 @@
                 </plugins>
             </build>
         </profile>
+        <profile>
+            <id>scan</id>
+            <build>
+                <plugins>
+                    <plugin>
+                        <groupId>org.owasp</groupId>
+                        <artifactId>dependency-check-maven</artifactId>
+                        <version>12.1.1</version>
+                        <!-- mvn -Pscan org.owasp:dependency-check-maven:check -->
+                        <executions>
+                            <execution>
+                                <goals>
+                                    <goal>check</goal>
+                                </goals>
+                            </execution>
+                        </executions>
+                    </plugin>
+                </plugins>
+            </build>
+        </profile>
     </profiles>
 
     <reporting>
@@ -1524,7 +1544,7 @@
             <dependency>
                 <groupId>org.glassfish.hk2</groupId>
                 <artifactId>osgi-resource-locator</artifactId>
-                <version>1.0.3</version>
+                <version>1.0.3</version> <!-- JDK 17 needed for 1.0.4 -->
             </dependency>
             <dependency>
                 <groupId>org.glassfish.main.hk2</groupId>
@@ -2071,16 +2091,16 @@
 
         <!-- Versions of Maven plugins -->
         <antrun.mvn.plugin.version>3.1.0</antrun.mvn.plugin.version>
-        <mvn.ant.version>1.10.14</mvn.ant.version>
+        <mvn.ant.version>1.10.15</mvn.ant.version>
         <assembly.mvn.plugin.version>3.7.1</assembly.mvn.plugin.version>
-        <clean.mvn.plugin.version>3.4.0</clean.mvn.plugin.version>
+        <clean.mvn.plugin.version>3.4.1</clean.mvn.plugin.version>
         <enforcer.mvn.plugin.version>3.5.0</enforcer.mvn.plugin.version>
-        <exec.mvn.plugin.version>3.4.1</exec.mvn.plugin.version>
+        <exec.mvn.plugin.version>3.5.0</exec.mvn.plugin.version>
         <buildhelper.mvn.plugin.version>3.6.0</buildhelper.mvn.plugin.version>
-        <buildnumber.mvn.plugin.version>3.2.0</buildnumber.mvn.plugin.version>
-        <checkstyle.mvn.plugin.version>3.4.0</checkstyle.mvn.plugin.version>
-        <checkstyle.version>10.17.0</checkstyle.version>
-        <compiler.mvn.plugin.version>3.13.0</compiler.mvn.plugin.version>
+        <buildnumber.mvn.plugin.version>3.2.1</buildnumber.mvn.plugin.version>
+        <checkstyle.mvn.plugin.version>3.6.0</checkstyle.mvn.plugin.version>
+        <checkstyle.version>10.21.4</checkstyle.version>
+        <compiler.mvn.plugin.version>3.14.0</compiler.mvn.plugin.version>
         <!--
         Special version of the compiler plugin just for the jersey-common. All versions above
         generate too much for OSGi manifest.mf imports (awt etc). The version 3.11.0 however
@@ -2089,24 +2109,24 @@
          -->
         <compiler.common.mvn.plugin.version>3.9.0</compiler.common.mvn.plugin.version>
         <cyclonedx.mvn.plugin.version>2.8.1</cyclonedx.mvn.plugin.version>
-        <dependency.mvn.plugin.version>3.7.1</dependency.mvn.plugin.version>
-        <deploy.mvn.plugin.version>3.1.2</deploy.mvn.plugin.version>
+        <dependency.mvn.plugin.version>3.8.1</dependency.mvn.plugin.version>
+        <deploy.mvn.plugin.version>3.1.4</deploy.mvn.plugin.version>
         <ear.mvn.plugin.version>3.3.0</ear.mvn.plugin.version>
-        <failsafe.mvn.plugin.version>3.3.1</failsafe.mvn.plugin.version>
+        <failsafe.mvn.plugin.version>3.5.3</failsafe.mvn.plugin.version>
         <felix.mvn.plugin.version>5.1.9</felix.mvn.plugin.version>
         <findbugs.mvn.plugin.version>3.0.5</findbugs.mvn.plugin.version>
         <gfembedded.mvn.plugin.version>5.1</gfembedded.mvn.plugin.version>
-        <install.mvn.plugin.version>3.1.2</install.mvn.plugin.version>
+        <install.mvn.plugin.version>3.1.4</install.mvn.plugin.version>
         <istack.mvn.plugin.version>4.2.0</istack.mvn.plugin.version>
         <jar.mvn.plugin.version>3.4.2</jar.mvn.plugin.version>
-        <javadoc.mvn.plugin.version>3.8.0</javadoc.mvn.plugin.version>
-        <jxr.mvn.plugin.version>3.4.0</jxr.mvn.plugin.version>
+        <javadoc.mvn.plugin.version>3.11.2</javadoc.mvn.plugin.version>
+        <jxr.mvn.plugin.version>3.6.0</jxr.mvn.plugin.version>
         <paxexam.mvn.plugin.version>1.2.4</paxexam.mvn.plugin.version>
-        <project.info.reports.mvn.plugin.version>3.6.2</project.info.reports.mvn.plugin.version>
+        <project.info.reports.mvn.plugin.version>3.9.0</project.info.reports.mvn.plugin.version>
         <resources.mvn.plugin.version>3.3.1</resources.mvn.plugin.version>
         <shade.mvn.plugin.version>3.6.0</shade.mvn.plugin.version>
         <source.mvn.plugin.version>3.3.1</source.mvn.plugin.version>
-        <surefire.mvn.plugin.version>3.5.2</surefire.mvn.plugin.version>
+        <surefire.mvn.plugin.version>3.5.3</surefire.mvn.plugin.version>
         <war.mvn.plugin.version>3.4.0</war.mvn.plugin.version>
         <wiremock.mvn.plugin.version>2.11.0</wiremock.mvn.plugin.version>
         <xml.mvn.plugin.version>1.1.0</xml.mvn.plugin.version>
@@ -2119,45 +2139,44 @@
         <arquillian.weld.version>3.0.1.Final</arquillian.weld.version> <!-- 3.0.2.Final fails microprofile TCK tests -->
         <!-- asm is now source integrated - keeping this property to see the version -->
         <!-- see core-server/src/main/java/jersey/repackaged/asm/.. -->
-        <asm.version>9.7.1</asm.version>
+        <asm.version>9.8</asm.version>
         <!--required for spring (ext) modules integration -->
         <aspectj.weaver.version>1.9.22.1</aspectj.weaver.version>
         <!--        <bnd.plugin.version>2.3.6</bnd.plugin.version>-->
         <bouncycastle.version>1.70</bouncycastle.version>
-        <commons.io.version>2.16.1</commons.io.version>
-        <commons.codec.version>1.16.1</commons.codec.version>
+        <commons.codec.version>1.18.0</commons.codec.version>
 <!--        <commons-lang3.version>3.3.2</commons-lang3.version>-->
-        <commons.logging.version>1.3.4</commons.logging.version>
+        <commons.logging.version>1.3.5</commons.logging.version>
         <fasterxml.classmate.version>1.7.0</fasterxml.classmate.version>
         <felix.eventadmin.version>1.6.4</felix.eventadmin.version>
         <felix.framework.security.version>2.8.4</felix.framework.security.version>
         <felix.framework.version>7.0.5</felix.framework.version>
         <findbugs.glassfish.version>1.7</findbugs.glassfish.version>
         <freemarker.version>2.3.33</freemarker.version>
-        <gae.version>2.0.29</gae.version>
-        <groovy.version>5.0.0-alpha-11</groovy.version>
-        <gson.version>2.11.0</gson.version>
+        <gae.version>2.0.36</gae.version>
+        <groovy.version>5.0.0-alpha-12</groovy.version>
+        <gson.version>2.13.1</gson.version>
 
         <!--versions, extracted here due to maven-enforcer-plugin -->
         <!--        <commons.codec.version>1.15</commons.codec.version>-->
         <com.uber.jaeger.version>0.27.0</com.uber.jaeger.version>
-        <org.codehaus.gmavenplus.version>3.0.2</org.codehaus.gmavenplus.version>
+        <org.codehaus.gmavenplus.version>4.2.0</org.codehaus.gmavenplus.version>
         <!-- end of versions extracted here due to maven-enforcer-plugin -->
 
         <!-- micrometer -->
-        <micrometer.version>1.12.4</micrometer.version>
+        <micrometer.version>1.15.0</micrometer.version>
         <micrometer-tracing.version>1.0.12</micrometer-tracing.version>
 
         <!-- microprofile -->
         <microprofile.config.version>3.0.3</microprofile.config.version>
         <microprofile.rest.client3.version>3.0.1</microprofile.rest.client3.version>
         <microprofile.rest.client.version>4.0</microprofile.rest.client.version>
-        <helidon.config.version>3.2.6</helidon.config.version>
-        <helidon.connector.version>3.2.8</helidon.connector.version>
-        <helidon.config.11.version>1.4.14</helidon.config.11.version> <!-- JDK 11- support -->
+        <helidon.config.version>3.2.12</helidon.config.version>
+        <helidon.connector.version>3.2.12</helidon.connector.version>
+        <helidon.config.11.version>1.4.15</helidon.config.11.version> <!-- JDK 11- support -->
         <smallrye.config.version>3.7.1</smallrye.config.version>
 
-        <guava.version>33.3.0-jre</guava.version>
+        <guava.version>33.4.8-jre</guava.version>
         <hamcrest.version>3.0</hamcrest.version>
         <xmlunit.version>2.10.0</xmlunit.version>
         <httpclient.version>4.5.14</httpclient.version>
@@ -2166,17 +2185,17 @@
         <javassist.version>3.30.2-GA</javassist.version>
         <jettison.version>1.3.7</jettison.version> <!-- TODO: 1.3.8 doesn't work; AbstractJsonTest complexBeanWithAttributes -->
         <jboss.vfs.version>3.3.2.Final</jboss.vfs.version>
-        <jboss.logging.version>3.6.0.Final</jboss.logging.version>
+        <jboss.logging.version>3.6.1.Final</jboss.logging.version>
         <jmh.version>1.37</jmh.version>
         <jmockit.version>1.49</jmockit.version>
         <junit4.version>4.13.2</junit4.version>
-        <junit5.version>5.11.4</junit5.version>
-        <junit-platform-suite.version>1.11.0</junit-platform-suite.version>
+        <junit5.version>5.12.2</junit5.version>
+        <junit-platform-suite.version>1.12.2</junit-platform-suite.version>
         <junit-platform-suite.legacy.version>1.10.0</junit-platform-suite.legacy.version>
         <kryo.version>4.0.3</kryo.version>
         <mockito.version>4.11.0</mockito.version> <!-- CQ 17673 -->
         <mustache.version>0.9.14</mustache.version>
-        <netty.version>4.1.112.Final</netty.version>
+        <netty.version>4.1.122.Final</netty.version>
         <opentracing.version>0.33.0</opentracing.version>
         <osgi.version>6.0.0</osgi.version>
         <osgi.framework.version>1.10.0</osgi.framework.version>
@@ -2192,9 +2211,9 @@
         <servlet6.version>6.0.0</servlet6.version>
 
         <simple.version>6.0.1</simple.version>
-        <slf4j.version>2.0.16</slf4j.version>
-        <spring6.version>6.0.18</spring6.version>
-        <testng.version>7.10.2</testng.version>
+        <slf4j.version>2.0.17</slf4j.version>
+        <spring6.version>6.0.23</spring6.version>
+        <testng.version>7.11.0</testng.version>
         <testng6.version>6.14.3</testng6.version>
         <thymeleaf.version>3.1.2.RELEASE</thymeleaf.version>
         <!-- Jakartified, eligible for CQ -->
@@ -2242,14 +2261,14 @@
         <jaxrs.api.spec.version>3.1</jaxrs.api.spec.version>
         <jaxrs.api.impl.version>3.1.0</jaxrs.api.impl.version>
         <jetty.osgi.version>org.eclipse.jetty.*;version="[11,15)"</jetty.osgi.version>
-        <jetty.version>12.0.14</jetty.version>
-        <jetty9.version>9.4.56.v20240826</jetty9.version>
-        <jetty11.version>11.0.24</jetty11.version>
-        <jetty.plugin.version>12.0.8</jetty.plugin.version>
+        <jetty.version>12.0.22</jetty.version>
+        <jetty9.version>9.4.57.v20241219</jetty9.version>
+        <jetty11.version>11.0.25</jetty11.version>
+        <jetty.plugin.version>12.0.22</jetty.plugin.version>
         <jsonb.api.version>3.0.1</jsonb.api.version>
         <jsonp.ri.version>1.1.7</jsonp.ri.version>
         <jsonp.jaxrs.version>1.1.7</jsonp.jaxrs.version>
-        <moxy.version>4.0.4</moxy.version>
+        <moxy.version>4.0.6</moxy.version>
         <yasson.version>3.0.4</yasson.version>
         <!-- END of Jakartified -->
 
diff --git a/security/oauth2-client/pom.xml b/security/oauth2-client/pom.xml
index 1b752a2..ae8fb37 100644
--- a/security/oauth2-client/pom.xml
+++ b/security/oauth2-client/pom.xml
@@ -47,18 +47,6 @@
 
 
     <dependencies>
-<!--        <dependency>-->
-<!--            <groupId>org.glassfish.jersey.media</groupId>-->
-<!--            <artifactId>jersey-media-json-jackson</artifactId>-->
-<!--            <version>${project.version}</version>-->
-<!--        </dependency>-->
-
-        <dependency>
-            <groupId>org.glassfish.jersey.media</groupId>
-            <artifactId>jersey-media-json-binding</artifactId>
-            <version>${project.version}</version>
-        </dependency>
-
         <dependency>
             <groupId>org.glassfish.jersey.core</groupId>
             <artifactId>jersey-client</artifactId>
@@ -70,11 +58,6 @@
                 </exclusion>
             </exclusions>
         </dependency>
-
-        <!--<dependency>-->
-            <!--<groupId>jakarta.ws.rs</groupId>-->
-            <!--<artifactId>jakarta.ws.rs-api</artifactId>-->
-        <!--</dependency>-->
     </dependencies>
 
 
diff --git a/test-framework/maven/container-runner-maven-plugin/pom.xml b/test-framework/maven/container-runner-maven-plugin/pom.xml
index 2790aed..50277c6 100644
--- a/test-framework/maven/container-runner-maven-plugin/pom.xml
+++ b/test-framework/maven/container-runner-maven-plugin/pom.xml
@@ -168,10 +168,10 @@
                     <groupId>org.codehaus.plexus</groupId>
                     <artifactId>plexus-archiver</artifactId>
                 </exclusion>
-                <exclusion>
+                <!--<exclusion>
                     <groupId>commons-io</groupId>
                     <artifactId>commons-io</artifactId>
-                </exclusion>
+                </exclusion>-->
                 <exclusion>
                     <groupId>org.junit.jupiter</groupId>
                     <artifactId>junit-jupiter-api</artifactId>
diff --git a/test-framework/maven/custom-enforcer-rules/pom.xml b/test-framework/maven/custom-enforcer-rules/pom.xml
index 439443e..9638c14 100644
--- a/test-framework/maven/custom-enforcer-rules/pom.xml
+++ b/test-framework/maven/custom-enforcer-rules/pom.xml
@@ -49,14 +49,14 @@
                     <artifactId>plexus-utils</artifactId>
                 </exclusion>
                 <exclusion>
-                    <groupId>commons-io</groupId>
-                    <artifactId>commons-io</artifactId>
-                </exclusion>
-                <exclusion>
                     <groupId>commons-codec</groupId>
                     <artifactId>commons-codec</artifactId>
                 </exclusion>
                 <exclusion>
+                    <groupId>commons-io</groupId>
+                    <artifactId>commons-io</artifactId>
+                </exclusion>
+                <exclusion>
                     <groupId>org.apache.maven</groupId>
                     <artifactId>maven-core</artifactId>
                 </exclusion>
@@ -68,12 +68,6 @@
         </dependency>
 
         <dependency>
-            <groupId>commons-io</groupId>
-            <artifactId>commons-io</artifactId>
-            <version>${commons.io.version}</version>
-        </dependency>
-
-        <dependency>
             <groupId>org.junit.jupiter</groupId>
             <artifactId>junit-jupiter</artifactId>
             <scope>compile</scope>
diff --git a/test-framework/maven/custom-enforcer-rules/src/main/java/org/glassfish/jersey/test/maven/rule/FilePatternDoesNotExistRule.java b/test-framework/maven/custom-enforcer-rules/src/main/java/org/glassfish/jersey/test/maven/rule/FilePatternDoesNotExistRule.java
index f9c8fde..ee275ba 100644
--- a/test-framework/maven/custom-enforcer-rules/src/main/java/org/glassfish/jersey/test/maven/rule/FilePatternDoesNotExistRule.java
+++ b/test-framework/maven/custom-enforcer-rules/src/main/java/org/glassfish/jersey/test/maven/rule/FilePatternDoesNotExistRule.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2023 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2025 Oracle and/or its affiliates. All rights reserved.
  *
  * This program and the accompanying materials are made available under the
  * terms of the Eclipse Public License v. 2.0, which is available at
@@ -17,17 +17,19 @@
 package org.glassfish.jersey.test.maven.rule;
 
 import java.io.File;
-import java.io.FileFilter;
+import java.io.IOException;
+import java.nio.file.DirectoryStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
 import java.util.Arrays;
 import java.util.Set;
 import java.util.TreeSet;
 
-import org.apache.commons.io.filefilter.WildcardFileFilter;
 import org.apache.maven.enforcer.rule.api.EnforcerRuleException;
 import org.apache.maven.enforcer.rules.AbstractStandardEnforcerRule;
 
 /**
- * Maven enforcer rule to enforce that given set of files does not exist.<br/>
+ * Maven enforcer rule to enforce that a given set of files does not exist.<br/>
  * This rule is similar to apache {@code requireFilesDontExist} with a support for wildcards.
  *
  * @author Stepan Vavra
@@ -55,8 +57,13 @@
             }
 
             final Set<File> matchedFiles = new TreeSet<>();
-            for (File matchedFile : dir.listFiles((FileFilter) new WildcardFileFilter(fileItselfPattern))) {
-                matchedFiles.add(matchedFile);
+            try {
+                final DirectoryStream<Path> directoryStream
+                        = Files.newDirectoryStream(dir.toPath(), fileItselfPattern);
+                directoryStream.forEach(path -> matchedFiles.add(path.toFile()));
+                directoryStream.close();
+            } catch (IOException e) {
+                throw new EnforcerRuleException(e);
             }
 
             if (!matchedFiles.isEmpty()) {
diff --git a/tests/e2e-client/pom.xml b/tests/e2e-client/pom.xml
index 963af19..3dce2ff 100644
--- a/tests/e2e-client/pom.xml
+++ b/tests/e2e-client/pom.xml
@@ -186,6 +186,19 @@
             <version>${project.version}</version>
             <scope>test</scope>
         </dependency>
+        <dependency>
+            <groupId>org.glassfish.jersey.media</groupId>
+            <artifactId>jersey-media-json-binding</artifactId>
+            <version>${project.version}</version>
+            <scope>test</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>org.glassfish.jersey.media</groupId>
+            <artifactId>jersey-media-json-jackson</artifactId>
+            <version>${project.version}</version>
+            <scope>test</scope>
+        </dependency>
 
         <dependency>
             <groupId>org.glassfish.jersey.test-framework</groupId>
@@ -208,11 +221,7 @@
             <version>${junit-platform-suite.version}</version>
             <scope>test</scope>
         </dependency>
-        <dependency>
-            <groupId>commons-io</groupId>
-            <artifactId>commons-io</artifactId>
-            <version>${commons.io.version}</version>
-        </dependency>
+
     </dependencies>
 
     <profiles>
diff --git a/tests/e2e-client/src/test/java/org/glassfish/jersey/tests/e2e/client/RedirectFileUploadServerTest.java b/tests/e2e-client/src/test/java/org/glassfish/jersey/tests/e2e/client/RedirectFileUploadServerTest.java
new file mode 100644
index 0000000..eddcba5
--- /dev/null
+++ b/tests/e2e-client/src/test/java/org/glassfish/jersey/tests/e2e/client/RedirectFileUploadServerTest.java
@@ -0,0 +1,217 @@
+/*
+ * Copyright (c) 2025 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package org.glassfish.jersey.tests.e2e.client;
+
+import com.sun.net.httpserver.HttpExchange;
+import com.sun.net.httpserver.HttpHandler;
+import com.sun.net.httpserver.HttpServer;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.net.InetSocketAddress;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.StandardCopyOption;
+import java.util.UUID;
+import java.util.concurrent.Executors;
+
+
+/**
+ * Server for the file upload test that redirects from /submit to /upload.
+ */
+class RedirectFileUploadServerTest {
+    private static final String UPLOAD_DIRECTORY = "target/uploads";
+    private static final String BOUNDARY_PREFIX = "boundary=";
+    private static final Path uploadDir = Paths.get(UPLOAD_DIRECTORY);
+
+    private static HttpServer server;
+
+
+    static void start(int port) throws IOException {
+        // Create upload directory if it doesn't exist
+        if (!Files.exists(uploadDir)) {
+            Files.createDirectory(uploadDir);
+        }
+
+        // Create HTTP server
+        server = HttpServer.create(new InetSocketAddress(port), 0);
+
+        // Create contexts for different endpoints
+        server.createContext("/submit", new SubmitHandler());
+        server.createContext("/upload", new UploadHandler());
+
+        // Set executor and start server
+        server.setExecutor(Executors.newFixedThreadPool(10));
+        server.start();
+        System.out.println("Server running on port " + port);
+    }
+
+    public static void stop() {
+        server.stop(0);
+    }
+
+
+    // Handler for /submit endpoint that redirects to /upload
+    static class SubmitHandler implements HttpHandler {
+        @Override
+        public void handle(HttpExchange exchange) throws IOException {
+            try {
+                if (!"POST".equals(exchange.getRequestMethod())) {
+                    sendResponse(exchange, 405, "Method Not Allowed. Only POST is supported.");
+                    return;
+                }
+
+                final BufferedReader reader
+                        = new BufferedReader(new InputStreamReader(exchange.getRequestBody(), StandardCharsets.UTF_8));
+                while (reader.readLine() != null) {
+                    //discard payload - required for JDK 1.8
+                }
+                reader.close();
+
+                // Send a 307 Temporary Redirect to /upload
+                // This preserves the POST method and body in the redirect
+                exchange.getResponseHeaders().add("Location", "/upload");
+                exchange.sendResponseHeaders(307, -1);
+            } finally {
+                exchange.close();
+            }
+        }
+    }
+
+    // Handler for /upload endpoint that processes file uploads
+    static class UploadHandler implements HttpHandler {
+        @Override
+        public void handle(HttpExchange exchange) throws IOException {
+            try {
+                if (!"POST".equals(exchange.getRequestMethod())) {
+                    sendResponse(exchange, 405, "Method Not Allowed. Only POST is supported.");
+                    return;
+                }
+
+                // Check if the request contains multipart form data
+                String contentType = exchange.getRequestHeaders().getFirst("Content-Type");
+                if (contentType == null || !contentType.startsWith("multipart/form-data")) {
+                    sendResponse(exchange, 400, "Bad Request. Content type must be multipart/form-data.");
+                    return;
+                }
+
+                // Extract boundary from content type
+                String boundary = extractBoundary(contentType);
+                if (boundary == null) {
+                    sendResponse(exchange, 400, "Bad Request. Could not determine boundary.");
+                    return;
+                }
+
+                // Process the multipart request and save the file
+                String fileName = processMultipartRequest(exchange, boundary);
+
+                if (fileName != null) {
+                    sendResponse(exchange, 200, "File uploaded successfully: " + fileName);
+                } else {
+                    sendResponse(exchange, 400, "Bad Request. No file found in request.");
+                }
+            } catch (Exception e) {
+                e.printStackTrace();
+                sendResponse(exchange, 500, "Internal Server Error: " + e.getMessage());
+            } finally {
+                exchange.close();
+                Files.deleteIfExists(uploadDir);
+            }
+        }
+
+        private String extractBoundary(String contentType) {
+            int boundaryIndex = contentType.indexOf(BOUNDARY_PREFIX);
+            if (boundaryIndex != -1) {
+                return "--" + contentType.substring(boundaryIndex + BOUNDARY_PREFIX.length());
+            }
+            return null;
+        }
+
+        private String processMultipartRequest(HttpExchange exchange, String boundary) throws IOException {
+            InputStream requestBody = exchange.getRequestBody();
+            BufferedReader reader = new BufferedReader(new InputStreamReader(requestBody, StandardCharsets.UTF_8));
+
+            String line;
+            String fileName = null;
+            Path tempFile = null;
+            boolean isFileContent = false;
+
+            // Generate a random filename for the temporary file
+            String tempFileName = UUID.randomUUID().toString();
+            tempFile = Files.createTempFile(tempFileName, ".tmp");
+
+            try (OutputStream fileOut = Files.newOutputStream(tempFile)) {
+                while ((line = reader.readLine()) != null) {
+                    // Check for the boundary
+                    if (line.startsWith(boundary)) {
+                        if (isFileContent) {
+                            // We've reached the end of the file content
+                            break;
+                        }
+
+                        // Read the next line (Content-Disposition)
+                        line = reader.readLine();
+                        if (line != null && line.startsWith("Content-Type")) {
+                            line = reader.readLine();
+                        }
+                        if (line != null && line.contains("filename=")) {
+                            // Extract filename
+                            int filenameStart = line.indexOf("filename=\"") + 10;
+                            int filenameEnd = line.indexOf("\"", filenameStart);
+                            fileName = line.substring(filenameStart, filenameEnd);
+
+                            // Skip Content-Type line and empty line
+                            reader.readLine(); // Content-Type
+//                            System.out.println(reader.readLine()); // Empty line
+                            isFileContent = true;
+                        }
+                    } else if (isFileContent) {
+                        // If we're reading file content and this line is not a boundary,
+                        // write it to the file (append a newline unless it's the first line)
+                        fileOut.write(line.getBytes(StandardCharsets.UTF_8));
+                        fileOut.write('\n');
+                    }
+                }
+            }
+
+            // If we found a file, move it from the temp location to the uploads directory
+            if (fileName != null && !fileName.isEmpty()) {
+                Path targetPath = Paths.get(UPLOAD_DIRECTORY, fileName);
+                Files.move(tempFile, targetPath, StandardCopyOption.REPLACE_EXISTING);
+                return fileName;
+            } else {
+                // If no file was found, delete the temp file
+                Files.deleteIfExists(tempFile);
+                return null;
+            }
+        }
+    }
+
+    // Helper method to send HTTP responses
+    private static void sendResponse(HttpExchange exchange, int statusCode, String response) throws IOException {
+        exchange.getResponseHeaders().set("Content-Type", "text/plain; charset=UTF-8");
+        exchange.sendResponseHeaders(statusCode, response.length());
+        try (OutputStream os = exchange.getResponseBody()) {
+            os.write(response.getBytes(StandardCharsets.UTF_8));
+        }
+    }
+}
\ No newline at end of file
diff --git a/tests/e2e-client/src/test/java/org/glassfish/jersey/tests/e2e/client/RedirectLargeFileTest.java b/tests/e2e-client/src/test/java/org/glassfish/jersey/tests/e2e/client/RedirectLargeFileTest.java
new file mode 100644
index 0000000..52e6cd2
--- /dev/null
+++ b/tests/e2e-client/src/test/java/org/glassfish/jersey/tests/e2e/client/RedirectLargeFileTest.java
@@ -0,0 +1,115 @@
+/*
+ * Copyright (c) 2025 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package org.glassfish.jersey.tests.e2e.client;
+
+import jakarta.ws.rs.client.Client;
+import jakarta.ws.rs.client.ClientBuilder;
+import jakarta.ws.rs.client.Entity;
+import jakarta.ws.rs.core.MediaType;
+import jakarta.ws.rs.core.Response;
+
+import com.fasterxml.jackson.core.JsonFactory;
+import com.fasterxml.jackson.core.JsonGenerator;
+import org.glassfish.jersey.client.ClientConfig;
+import org.glassfish.jersey.media.multipart.FormDataBodyPart;
+import org.glassfish.jersey.media.multipart.FormDataContentDisposition;
+import org.glassfish.jersey.media.multipart.FormDataMultiPart;
+import org.glassfish.jersey.media.multipart.MultiPartFeature;
+import org.glassfish.jersey.netty.connector.NettyConnectorProvider;
+import org.junit.jupiter.api.AfterAll;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+
+import java.io.FileWriter;
+import java.io.IOException;
+import java.net.URL;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+
+public class RedirectLargeFileTest {
+
+    private static final int SERVER_PORT = 9997;
+    private static final String SERVER_ADDR = String.format("http://localhost:%d/submit", SERVER_PORT);
+
+    Client client() {
+        final ClientConfig config = new ClientConfig();
+        config.connectorProvider(new NettyConnectorProvider());
+        config.register(MultiPartFeature.class);
+        return ClientBuilder.newClient(config);
+    }
+
+    @BeforeAll
+    static void startServer() throws Exception{
+        RedirectFileUploadServerTest.start(SERVER_PORT);
+    }
+
+    @AfterAll
+    static void stopServer() {
+        RedirectFileUploadServerTest.stop();
+    }
+
+    @Test
+    void sendFileTest() throws Exception {
+
+        final String fileName = "bigFile.json";
+        final String path = "target/" + fileName;
+
+        final Path pathResource = Paths.get(path);
+        try {
+            final Path realFilePath = Files.createFile(pathResource.toAbsolutePath());
+
+            generateJson(realFilePath.toString(), 1000000); // 33Mb real file size
+
+            final byte[] content = Files.readAllBytes(realFilePath);
+
+            final FormDataMultiPart mp = new FormDataMultiPart();
+            mp.bodyPart(new FormDataBodyPart(FormDataContentDisposition.name(fileName).fileName(fileName).build(),
+                    content,
+                    MediaType.TEXT_PLAIN_TYPE));
+
+            try (final Response response = client().target(SERVER_ADDR).request()
+                    .post(Entity.entity(mp, MediaType.MULTIPART_FORM_DATA_TYPE))) {
+                Assertions.assertEquals(200, response.getStatus());
+            }
+        } finally {
+            Files.deleteIfExists(pathResource);
+        }
+    }
+
+    private static void generateJson(final String filePath, int recordCount) throws Exception {
+
+        try (final JsonGenerator generator = new JsonFactory().createGenerator(new FileWriter(filePath))) {
+            generator.writeStartArray();
+
+            for (int i = 0; i < recordCount; i++) {
+                generator.writeStartObject();
+                generator.writeNumberField("id", i);
+                generator.writeStringField("name", "User" + i);
+                // Add more fields as needed
+                generator.writeEndObject();
+
+                if (i % 10000 == 0) {
+                    generator.flush();
+                }
+            }
+
+            generator.writeEndArray();
+        }
+    }
+}
diff --git a/tests/e2e-client/src/test/java/org/glassfish/jersey/tests/e2e/client/connector/ssl/AbstractConnectorServerTest.java b/tests/e2e-client/src/test/java/org/glassfish/jersey/tests/e2e/client/connector/ssl/AbstractConnectorServerTest.java
index 0fde39c..05b4267 100644
--- a/tests/e2e-client/src/test/java/org/glassfish/jersey/tests/e2e/client/connector/ssl/AbstractConnectorServerTest.java
+++ b/tests/e2e-client/src/test/java/org/glassfish/jersey/tests/e2e/client/connector/ssl/AbstractConnectorServerTest.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2023 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2025 Oracle and/or its affiliates. All rights reserved.
  *
  * This program and the accompanying materials are made available under the
  * terms of the Eclipse Public License v. 2.0, which is available at
@@ -31,11 +31,10 @@
 import org.glassfish.jersey.jetty.connector.JettyConnectorProvider;
 import org.glassfish.jersey.jnh.connector.JavaNetHttpConnectorProvider;
 
+import org.glassfish.jersey.message.internal.ReaderWriter;
 import org.junit.jupiter.api.AfterEach;
 import org.junit.jupiter.api.BeforeEach;
 
-import org.apache.commons.io.IOUtils;
-
 /**
  * SSL connector hostname verification tests.
  *
@@ -95,9 +94,9 @@
         final InputStream trustStore = SslConnectorConfigurationTest.class.getResourceAsStream(clientTrustStore());
         final InputStream keyStore = SslConnectorConfigurationTest.class.getResourceAsStream(CLIENT_KEY_STORE);
         return SslConfigurator.newInstance()
-                .trustStoreBytes(IOUtils.toByteArray(trustStore))
+                .trustStoreBytes(ReaderWriter.readFromAsBytes(trustStore))
                 .trustStorePassword("asdfgh")
-                .keyStoreBytes(IOUtils.toByteArray(keyStore))
+                .keyStoreBytes(ReaderWriter.readFromAsBytes(keyStore))
                 .keyPassword("asdfgh")
                 .createSSLContext();
     }
diff --git a/tests/e2e-client/src/test/java/org/glassfish/jersey/tests/e2e/client/connector/ssl/Server.java b/tests/e2e-client/src/test/java/org/glassfish/jersey/tests/e2e/client/connector/ssl/Server.java
index 20795c3..b66ff73 100644
--- a/tests/e2e-client/src/test/java/org/glassfish/jersey/tests/e2e/client/connector/ssl/Server.java
+++ b/tests/e2e-client/src/test/java/org/glassfish/jersey/tests/e2e/client/connector/ssl/Server.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010, 2022 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2010, 2025 Oracle and/or its affiliates. All rights reserved.
  *
  * This program and the accompanying materials are made available under the
  * terms of the Eclipse Public License v. 2.0, which is available at
@@ -23,9 +23,9 @@
 
 import jakarta.ws.rs.core.UriBuilder;
 
-import org.apache.commons.io.IOUtils;
 import org.glassfish.jersey.logging.LoggingFeature;
 import org.glassfish.jersey.grizzly2.httpserver.GrizzlyHttpServerFactory;
+import org.glassfish.jersey.message.internal.ReaderWriter;
 import org.glassfish.jersey.server.ResourceConfig;
 
 import org.glassfish.grizzly.http.server.HttpServer;
@@ -86,9 +86,9 @@
         SSLContextConfigurator sslContext = new SSLContextConfigurator();
 
         // set up security context
-        sslContext.setKeyStoreBytes(IOUtils.toByteArray(keyStore));  // contains server key pair
+        sslContext.setKeyStoreBytes(ReaderWriter.readFromAsBytes(keyStore));  // contains server key pair
         sslContext.setKeyStorePass("asdfgh");
-        sslContext.setTrustStoreBytes(IOUtils.toByteArray(trustStore)); // contains client certificate
+        sslContext.setTrustStoreBytes(ReaderWriter.readFromAsBytes(trustStore)); // contains client certificate
         sslContext.setTrustStorePass("asdfgh");
 
         ResourceConfig rc = new ResourceConfig();
diff --git a/tests/e2e-client/src/test/java/org/glassfish/jersey/tests/e2e/client/nettyconnector/Expect100ContinueTest.java b/tests/e2e-client/src/test/java/org/glassfish/jersey/tests/e2e/client/nettyconnector/Expect100ContinueTest.java
index ffb8b1f..426b494 100644
--- a/tests/e2e-client/src/test/java/org/glassfish/jersey/tests/e2e/client/nettyconnector/Expect100ContinueTest.java
+++ b/tests/e2e-client/src/test/java/org/glassfish/jersey/tests/e2e/client/nettyconnector/Expect100ContinueTest.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2020, 2024 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2020, 2025 Oracle and/or its affiliates. All rights reserved.
  *
  * This program and the accompanying materials are made available under the
  * terms of the Eclipse Public License v. 2.0, which is available at
@@ -16,33 +16,48 @@
 
 package org.glassfish.jersey.tests.e2e.client.nettyconnector;
 
-import org.eclipse.jetty.server.Handler;
-import org.eclipse.jetty.server.Request;
-import org.eclipse.jetty.server.Server;
-import org.eclipse.jetty.util.Callback;
 import org.glassfish.jersey.client.ClientConfig;
 import org.glassfish.jersey.client.ClientProperties;
 import org.glassfish.jersey.client.RequestEntityProcessing;
 import org.glassfish.jersey.client.http.Expect100ContinueFeature;
 import org.glassfish.jersey.netty.connector.NettyClientProperties;
 import org.glassfish.jersey.netty.connector.NettyConnectorProvider;
-import org.junit.jupiter.api.AfterAll;
+import org.junit.jupiter.api.AfterEach;
 import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 
+import javax.net.ServerSocketFactory;
 import jakarta.ws.rs.ProcessingException;
+import jakarta.ws.rs.client.AsyncInvoker;
 import jakarta.ws.rs.client.Client;
 import jakarta.ws.rs.client.ClientBuilder;
 import jakarta.ws.rs.client.Entity;
+import jakarta.ws.rs.client.Invocation;
+import jakarta.ws.rs.client.InvocationCallback;
 import jakarta.ws.rs.client.WebTarget;
 import jakarta.ws.rs.core.HttpHeaders;
 import jakarta.ws.rs.core.Response;
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
 import java.io.IOException;
-import java.nio.ByteBuffer;
+import java.io.InputStreamReader;
+import java.io.OutputStreamWriter;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.util.HashMap;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Random;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
 
 import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertNotNull;
 import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.fail;
 
 public class Expect100ContinueTest /*extends JerseyTest*/ {
 
@@ -57,187 +72,385 @@
     private static final String RESOURCE_PATH_METHOD_NOT_SUPPORTED = "fail405";
 
     private static final String ENTITY_STRING = "1234567890123456789012345678901234567890123456789012"
-           + "3456789012345678901234567890";
+            + "3456789012345678901234567890";
 
     private static final Integer portNumber = 9997;
 
-    private static Server server;
-    @BeforeAll
-    private static void startExpect100ContinueTestServer() {
-        server = new Server(portNumber);
-        server.setDefaultHandler(new Expect100ContinueTestHandler());
-        server.setDynamic(true);
-        try {
-            server.start();
-        } catch (Exception e) {
+    private static TestSocketServer server;
 
-        }
-    }
-
-    @AfterAll
-    private static void stopExpect100ContinueTestServer() {
-        try {
-            server.stop();
-        } catch (Exception e) {
-        }
-    }
+    private static Client client;
 
     @BeforeAll
-    private static void initClient() {
+    static void beforeAll() {
         final ClientConfig config = new ClientConfig();
         config.connectorProvider(new NettyConnectorProvider());
         client = ClientBuilder.newClient(config);
     }
 
-    @AfterAll
-    private static void stopClient() {
-        client.close();
+    @BeforeEach
+    void beforeEach() throws IOException {
+        server = new TestSocketServer(portNumber);
+        server.runServer();
     }
 
-    private static Client client;
+    @AfterEach
+    void afterEach() {
+        server.stop();
+    }
+
     public WebTarget target(String path) {
         return client.target(String.format("http://localhost:%d", portNumber)).path(path);
     }
 
     @Test
     public void testExpect100Continue() {
-       final Response response =  target(RESOURCE_PATH).request().post(Entity.text(ENTITY_STRING));
-       assertEquals(200, response.getStatus(), "Expected 200"); //no Expect header sent - response OK
+        final Response response = target(RESOURCE_PATH).request().post(Entity.text(ENTITY_STRING));
+        assertEquals(200, response.getStatus(), "Expected 200"); //no Expect header sent - response OK
     }
 
     @Test
     public void testExpect100ContinueChunked() {
-       final Response response =  target(RESOURCE_PATH).register(Expect100ContinueFeature.basic())
-               .property(ClientProperties.REQUEST_ENTITY_PROCESSING,
-               RequestEntityProcessing.CHUNKED).request().post(Entity.text(ENTITY_STRING));
-       assertEquals(204, response.getStatus(), "Expected 204"); //Expect header sent - No Content response
+            final Response response = target(RESOURCE_PATH).register(Expect100ContinueFeature.basic())
+                    .property(ClientProperties.REQUEST_ENTITY_PROCESSING,
+                            RequestEntityProcessing.CHUNKED)
+                    .request().post(Entity.text(ENTITY_STRING));
+            assertEquals(204, response.getStatus(), "Expected 204"); //Expect header sent - No Content response
+    }
+
+    @Test
+    public void testExpect100ContinueManyAsyncRequests() {
+
+        final Invocation.Builder requestBuilder = target(RESOURCE_PATH).register(Expect100ContinueFeature.basic())
+                .property(ClientProperties.REQUEST_ENTITY_PROCESSING,
+                        RequestEntityProcessing.CHUNKED)
+                .request();
+        final AsyncInvoker invoker =
+                requestBuilder.async();
+
+        final InvocationCallback<Response> responseCallback = new InvocationCallback<Response>() {
+            @Override
+            public void completed(Response response) {
+                assertEquals(204, response.getStatus(), "Expected 204"); //Expect header sent - No Content response
+            }
+
+            @Override
+            public void failed(Throwable throwable) {
+                fail(throwable); // should not fail
+            }
+        };
+        invoker.post(Entity.text(ENTITY_STRING), responseCallback);
+        invoker.post(Entity.text(ENTITY_STRING), responseCallback);
+        invoker.post(Entity.text(ENTITY_STRING), responseCallback);
+        invoker.post(Entity.text(ENTITY_STRING), responseCallback);
+        invoker.post(Entity.text(ENTITY_STRING), responseCallback);
+        invoker.post(Entity.text(ENTITY_STRING), responseCallback);
+
+        final Response response = requestBuilder.post(Entity.text(ENTITY_STRING));
+        assertEquals(204, response.getStatus(), "Expected 204"); //Expect header sent - No Content response
     }
 
     @Test
     public void testExpect100ContinueBuffered() {
-       final Response response =  target(RESOURCE_PATH).register(Expect100ContinueFeature.basic())
-               .property(ClientProperties.REQUEST_ENTITY_PROCESSING,
-               RequestEntityProcessing.BUFFERED).request().header(HttpHeaders.CONTENT_LENGTH, 67000L)
-               .post(Entity.text(ENTITY_STRING));
-       assertEquals(204, response.getStatus(), "Expected 204"); //Expect header sent - No Content response
+            final Response response = target(RESOURCE_PATH).register(Expect100ContinueFeature.basic())
+                    .property(ClientProperties.REQUEST_ENTITY_PROCESSING,
+                            RequestEntityProcessing.BUFFERED).request().header(HttpHeaders.CONTENT_LENGTH, 67000L)
+                    .post(Entity.text(generateStringByContentLength(67000)));
+            assertEquals(204, response.getStatus(), "Expected 204"); //Expect header sent - No Content response
     }
 
     @Test
     public void testExpect100ContinueCustomLength() {
-       final Response response =  target(RESOURCE_PATH).register(Expect100ContinueFeature.withCustomThreshold(100L))
-               .request().header(HttpHeaders.CONTENT_LENGTH, Integer.MAX_VALUE)
-               .post(Entity.text(ENTITY_STRING));
-       assertEquals(204, response.getStatus(), "Expected 204"); //Expect header sent - No Content response
+            final Response response = target(RESOURCE_PATH).register(Expect100ContinueFeature.withCustomThreshold(100L))
+                    .request().header(HttpHeaders.CONTENT_LENGTH, 200)
+                    .post(Entity.text(generateStringByContentLength(200)));
+            assertEquals(204, response.getStatus(), "Expected 204"); //Expect header sent - No Content response
     }
 
     @Test
     public void testExpect100ContinueCustomLengthWrong() {
-       final Response response =  target(RESOURCE_PATH).register(Expect100ContinueFeature.withCustomThreshold(100L))
-               .request().header(HttpHeaders.CONTENT_LENGTH, 99L)
-               .post(Entity.text(ENTITY_STRING));
-       assertEquals(200, response.getStatus(), "Expected 200"); //Expect header NOT sent - low request size
+            final Response response = target(RESOURCE_PATH).register(Expect100ContinueFeature.withCustomThreshold(100L))
+                    .request().header(HttpHeaders.CONTENT_LENGTH, 99L)
+                    .post(Entity.text(generateStringByContentLength(99)));
+            assertEquals(200, response.getStatus(), "Expected 200"); //Expect header NOT sent - low request size
     }
 
     @Test
     public void testExpect100ContinueCustomLengthProperty() {
-       final Response response =  target(RESOURCE_PATH)
-               .property(ClientProperties.EXPECT_100_CONTINUE_THRESHOLD_SIZE, 555L)
-               .property(ClientProperties.EXPECT_100_CONTINUE, Boolean.TRUE)
-               .register(Expect100ContinueFeature.withCustomThreshold(555L))
-               .request().header(HttpHeaders.CONTENT_LENGTH, 666L)
-               .post(Entity.text(ENTITY_STRING));
-       assertNotNull(response.getStatus()); //Expect header sent - No Content response
+            final Response response = target(RESOURCE_PATH)
+                    .property(ClientProperties.EXPECT_100_CONTINUE_THRESHOLD_SIZE, 555L)
+                    .property(ClientProperties.EXPECT_100_CONTINUE, Boolean.TRUE)
+                    .register(Expect100ContinueFeature.withCustomThreshold(555L))
+                    .request().header(HttpHeaders.CONTENT_LENGTH, 666L)
+                    .post(Entity.text(generateStringByContentLength(666)));
+            assertNotNull(response.getStatus()); //Expect header sent - No Content response
     }
 
     @Test
     public void testExpect100ContinueRegisterViaCustomProperty() {
-       final Response response =  target(RESOURCE_PATH)
-               .property(ClientProperties.EXPECT_100_CONTINUE_THRESHOLD_SIZE, 43L)
-               .property(ClientProperties.EXPECT_100_CONTINUE, Boolean.TRUE)
-               .request().header(HttpHeaders.CONTENT_LENGTH, 44L)
-               .post(Entity.text(ENTITY_STRING));
-       assertEquals(204, response.getStatus(), "Expected 204"); //Expect header sent - No Content response
+        final Response response = target(RESOURCE_PATH)
+                .property(ClientProperties.EXPECT_100_CONTINUE_THRESHOLD_SIZE, 43L)
+                .property(ClientProperties.EXPECT_100_CONTINUE, Boolean.TRUE)
+                .request().header(HttpHeaders.CONTENT_LENGTH, 44L)
+                .post(Entity.text(generateStringByContentLength(44)));
+        assertEquals(204, response.getStatus(), "Expected 204"); //Expect header sent - No Content response
     }
 
     @Test
     public void testExpect100ContinueNotSupported() {
-       final Response response =  target(RESOURCE_PATH_NOT_SUPPORTED)
-               .property(ClientProperties.EXPECT_100_CONTINUE_THRESHOLD_SIZE, 43L)
-               .property(ClientProperties.EXPECT_100_CONTINUE, Boolean.TRUE)
-               .request().header(HttpHeaders.CONTENT_LENGTH, 44L)
-               .post(Entity.text(ENTITY_STRING));
-       assertEquals(417, response.getStatus(), "Expected 417"); //Expectations not supported
+            final Response response = target(RESOURCE_PATH_NOT_SUPPORTED)
+                    .property(ClientProperties.EXPECT_100_CONTINUE_THRESHOLD_SIZE, 43L)
+                    .property(ClientProperties.EXPECT_100_CONTINUE, Boolean.TRUE)
+                    .request().header(HttpHeaders.CONTENT_LENGTH, 44L)
+                    .post(Entity.text(generateStringByContentLength(44)));
+            assertEquals(204, response.getStatus(),
+                    "This should re-send request without expect and obtain the 204 response code"); //Expectations not supported
     }
 
     @Test
     public void testExpect100ContinueUnauthorized() {
-       assertThrows(ProcessingException.class, () -> target(RESOURCE_PATH_UNAUTHORIZED)
-               .property(ClientProperties.EXPECT_100_CONTINUE_THRESHOLD_SIZE, 43L)
-               .property(ClientProperties.EXPECT_100_CONTINUE, Boolean.TRUE)
-               .property(NettyClientProperties.EXPECT_100_CONTINUE_TIMEOUT, 10000)
-               .request().header(HttpHeaders.CONTENT_LENGTH, 44L)
-               .post(Entity.text(ENTITY_STRING)));
+            assertThrows(ProcessingException.class, () -> target(RESOURCE_PATH_UNAUTHORIZED)
+                    .property(ClientProperties.EXPECT_100_CONTINUE_THRESHOLD_SIZE, 43L)
+                    .property(ClientProperties.EXPECT_100_CONTINUE, Boolean.TRUE)
+                    .property(NettyClientProperties.EXPECT_100_CONTINUE_TIMEOUT, 10000)
+                    .request().header(HttpHeaders.CONTENT_LENGTH, 44L)
+                    .post(Entity.text(generateStringByContentLength(44))));
     }
 
     @Test
     public void testExpect100ContinuePayloadTooLarge() {
         assertThrows(ProcessingException.class, () -> target(RESOURCE_PATH_PAYLOAD_TOO_LARGE)
-               .property(ClientProperties.EXPECT_100_CONTINUE_THRESHOLD_SIZE, 43L)
-               .property(ClientProperties.EXPECT_100_CONTINUE, Boolean.TRUE)
-               .property(NettyClientProperties.EXPECT_100_CONTINUE_TIMEOUT, 10000)
-               .request().header(HttpHeaders.CONTENT_LENGTH, 44L)
-               .post(Entity.text(ENTITY_STRING)));
+                .property(ClientProperties.EXPECT_100_CONTINUE_THRESHOLD_SIZE, 43L)
+                .property(ClientProperties.EXPECT_100_CONTINUE, Boolean.TRUE)
+                .property(NettyClientProperties.EXPECT_100_CONTINUE_TIMEOUT, 10000)
+                .request().header(HttpHeaders.CONTENT_LENGTH, 44L)
+                .post(Entity.text(generateStringByContentLength(44))));
     }
 
     @Test
     public void testExpect100ContinueMethodNotSupported() {
-        assertThrows(ProcessingException.class, () -> target(RESOURCE_PATH_METHOD_NOT_SUPPORTED)
-               .property(ClientProperties.EXPECT_100_CONTINUE_THRESHOLD_SIZE, 43L)
-               .property(ClientProperties.EXPECT_100_CONTINUE, Boolean.TRUE)
-               .property(NettyClientProperties.EXPECT_100_CONTINUE_TIMEOUT, 10000)
-               .request().header(HttpHeaders.CONTENT_LENGTH, 44L)
-               .post(Entity.text(ENTITY_STRING)));
+            assertThrows(ProcessingException.class, () ->  target(RESOURCE_PATH_METHOD_NOT_SUPPORTED)
+                    .property(ClientProperties.EXPECT_100_CONTINUE_THRESHOLD_SIZE, 43L)
+                    .property(ClientProperties.EXPECT_100_CONTINUE, Boolean.TRUE)
+                    .property(NettyClientProperties.EXPECT_100_CONTINUE_TIMEOUT, 10000)
+                    .request().header(HttpHeaders.CONTENT_LENGTH, 44L)
+                    .post(Entity.text(generateStringByContentLength(44))));
+
     }
 
-    static class Expect100ContinueTestHandler extends Handler.Abstract {
-        @Override
-        public boolean handle(Request request,
-                              org.eclipse.jetty.server.Response response,
-                              Callback callback) throws IOException {
-            boolean expected = request.getHeaders().contains("Expect");
-            boolean failed = false;
-            final String target = request.getHttpURI().getCanonicalPath();
-            if (target.equals("/" + RESOURCE_PATH_NOT_SUPPORTED)) {
-                response.setStatus(417);
-                failed = true;
-            }
-            if (target.equals("/" + RESOURCE_PATH_UNAUTHORIZED)) {
-                response.setStatus(401);
-                failed = true;
-            }
-            if (target.equals("/" + RESOURCE_PATH_PAYLOAD_TOO_LARGE)) {
-                response.setStatus(413);
-                failed = true;
-            }
-            if (target.equals("/" + RESOURCE_PATH_METHOD_NOT_SUPPORTED)) {
-                response.setStatus(405);
-                failed = true;
-            }
-            if (expected && !failed) {
-                System.out.println("Expect:100-continue found, sending response header");
-                response.setStatus(204);
-                callback.succeeded();
-                return true;
-            }
-            if (!expected && !failed) {
-                response.reset();
-                callback.succeeded();
-                return true;
-            }
-            response.write(true, ByteBuffer.wrap("\n\r".getBytes()), callback);
-
-            callback.failed(new ProcessingException(""));
-            return true;
+    private String generateStringByContentLength(int length) {
+        final char[] array = new char[length];
+        final Random r = new Random();
+        for (int i = 0; i < length; i++) {
+            array[i] = ENTITY_STRING.charAt(r.nextInt(ENTITY_STRING.length()));
         }
+        return String.valueOf(array);
+    }
+
+    private static final class TestSocketServer {
+
+        private static final String NO_CONTENT_HEADER = "HTTP/1.1 204 No Content";
+        private static final String OK_HEADER = "HTTP/1.1 200 OK";
+        private static final String EXPECT_HEADER = "HTTP/1.1 100 Continue";
+        private static final String UNAUTHORIZED_HEADER = "HTTP/1.1 401 Unauthorized";
+        private static final String NOT_SUPPORTED_HEADER = "HTTP/1.1 405 Method Not Allowed";
+        private static final String TOO_LARGE_HEADER = "HTTP/1.1 413 Request Entity Too Large";
+
+        private final ExecutorService executorService = Executors.newCachedThreadPool();
+        private AtomicBoolean unauthorized = new AtomicBoolean(false);
+        private AtomicBoolean not_supported = new AtomicBoolean(false);
+        private AtomicBoolean too_large = new AtomicBoolean(false);
+
+        private AtomicBoolean expect_processed = new AtomicBoolean(false);
+
+        private ServerSocket server;
+
+        private volatile boolean stopped = false;
+
+        public TestSocketServer(int port) throws IOException {
+            final ServerSocketFactory socketFactory = ServerSocketFactory.getDefault();
+            server = socketFactory.createServerSocket(port);
+        }
+
+        void stop() {
+            stopped = true;
+            try {
+                server.close();
+                executorService.shutdown();
+                while (!executorService.isTerminated()) {
+                    executorService.awaitTermination(100, TimeUnit.MILLISECONDS);
+                }
+            } catch (IOException | InterruptedException e) {
+                throw new RuntimeException(e);
+            }
+        }
+
+        void runServer() {
+
+            executorService.execute(() -> {
+                try {
+                    while (!stopped) {
+                        final Socket socket = server.accept();
+                        executorService.submit(() -> processRequest(socket));
+                    }
+                } catch (IOException e) {
+                    if (!stopped) {
+                        e.printStackTrace();
+                    }
+                }
+            });
+        }
+
+        private void processRequest(final Socket request) {
+            try (final BufferedReader reader = new BufferedReader(new InputStreamReader(request.getInputStream()));
+                 final BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(request.getOutputStream()))) {
+
+
+                while (!stopped) {
+                    final Map<String, String> headers = mapHeaders(reader);
+
+                    if (headers.isEmpty()) {
+                        continue;
+                    }
+
+                    boolean failed = processExpect100Continue(headers, writer);
+
+                    if (failed) {
+                        continue;
+                    }
+
+                    final String http_header = expect_processed.get() ? NO_CONTENT_HEADER : OK_HEADER;
+                    boolean read = readBody(reader, headers);
+
+                    final StringBuffer responseBuffer = new StringBuffer(http_header);
+                    addNewLineToResponse(responseBuffer);
+                    addServerHeaderToResponse(responseBuffer);
+                    addNewLineToResponse(responseBuffer);
+                    addNewLineToResponse(responseBuffer);
+
+                    writer.write(responseBuffer.toString());
+
+                    writer.flush();
+                    if (read) {
+                        break;
+                    }
+
+                }
+            } catch (Exception e) {
+                e.printStackTrace();
+            } finally {
+                try {
+                    request.close();
+                } catch (IOException e) {
+                    e.printStackTrace();
+                }
+            }
+        }
+
+        private void addNewLineToResponse(StringBuffer responseBuffer) {
+            addToResponse("\r\n", responseBuffer);
+        }
+
+        private void addToResponse(String toBeAdded, StringBuffer responseBuffer) {
+            responseBuffer.append(toBeAdded);
+        }
+
+        private void addServerHeaderToResponse(StringBuffer responseBuffer) {
+            addToResponse("Server: SocketServer v.0.0.1", responseBuffer);
+            addNewLineToResponse(responseBuffer);
+        }
+
+        private boolean processExpect100Continue(Map<String, String> headers, BufferedWriter writer) throws IOException {
+            String http_header = EXPECT_HEADER;
+            boolean failed = false;
+            final String continueHeader = headers.remove("expect");
+
+            if (continueHeader != null && continueHeader.contains("100-continue")) {
+
+                if (unauthorized.get()) {
+                    http_header = UNAUTHORIZED_HEADER;
+                    unauthorized.set(false);
+                    failed = true;
+                }
+
+                if (not_supported.get()) {
+                    http_header = NOT_SUPPORTED_HEADER;
+                    not_supported.set(false);
+                    failed = true;
+                }
+
+                if (too_large.get()) {
+                    http_header = TOO_LARGE_HEADER;
+                    too_large.set(false);
+                    failed = true;
+                }
+
+                expect_processed.set(http_header.equals(EXPECT_HEADER));
+
+
+                final StringBuffer responseBuffer = new StringBuffer(http_header);
+
+                addNewLineToResponse(responseBuffer);
+                addToResponse("Connection: keep-alive", responseBuffer);
+                addNewLineToResponse(responseBuffer);
+                addNewLineToResponse(responseBuffer);
+
+                writer.write(responseBuffer.toString());
+                writer.flush();
+            }
+            return failed;
+        }
+
+        private Map<String, String> mapHeaders(BufferedReader reader) throws IOException {
+            String line;
+            final Map<String, String> headers = new HashMap<>();
+
+
+            if (!reader.ready()) {
+                return headers;
+            }
+
+            while ((line = reader.readLine()) != null && !line.isEmpty()) {
+
+                if (line.contains(RESOURCE_PATH_UNAUTHORIZED)) {
+                    unauthorized.set(true);
+                }
+
+                if (line.contains(RESOURCE_PATH_METHOD_NOT_SUPPORTED)) {
+                    not_supported.set(true);
+                }
+
+                if (line.contains(RESOURCE_PATH_PAYLOAD_TOO_LARGE)) {
+                    too_large.set(true);
+                }
+
+                int pos = line.indexOf(':');
+                if (pos > -1) {
+                    headers.put(
+                            line.substring(0, pos).toLowerCase(Locale.ROOT),
+                            line.substring(pos + 2).toLowerCase(Locale.ROOT).trim());
+                }
+            }
+
+            return headers;
+        }
+
+        private boolean readBody(BufferedReader reader, Map<String, String> headers) throws IOException, InterruptedException {
+            if (headers.containsKey("content-length")) {
+                int contentLength = Integer.valueOf(headers.get("content-length"));
+                int actualLength = 0, readingByte = 0;
+                int[] buffer = new int[contentLength];
+                while (actualLength < contentLength && (readingByte = reader.read()) != -1) {
+                    buffer[actualLength++] = readingByte;
+                }
+                return (actualLength == contentLength);
+            } else if (headers.containsKey("transfer-encoding")) {
+                String line;
+                while ((line = reader.readLine()) != null && !line.equals("0")) {
+                }
+                return true;
+            }
+            return false;
+        }
+
     }
 }
\ No newline at end of file
diff --git a/tests/e2e-core-common/src/test/java/org/glassfish/jersey/tests/e2e/common/process/internal/RequestScopeTest.java b/tests/e2e-core-common/src/test/java/org/glassfish/jersey/tests/e2e/common/process/internal/RequestScopeTest.java
index 7582894..d0488fa 100644
--- a/tests/e2e-core-common/src/test/java/org/glassfish/jersey/tests/e2e/common/process/internal/RequestScopeTest.java
+++ b/tests/e2e-core-common/src/test/java/org/glassfish/jersey/tests/e2e/common/process/internal/RequestScopeTest.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2022 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2025 Oracle and/or its affiliates. All rights reserved.
  *
  * This program and the accompanying materials are made available under the
  * terms of the Eclipse Public License v. 2.0, which is available at
@@ -17,6 +17,8 @@
 package org.glassfish.jersey.tests.e2e.common.process.internal;
 
 import java.lang.reflect.Type;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.function.Consumer;
 
 import org.glassfish.jersey.inject.hk2.Hk2RequestScope;
 import org.glassfish.jersey.internal.inject.ForeignDescriptor;
@@ -25,6 +27,7 @@
 import org.glassfish.hk2.api.ServiceHandle;
 import org.glassfish.hk2.utilities.AbstractActiveDescriptor;
 
+import org.junit.jupiter.api.Assertions;
 import org.junit.jupiter.api.Test;
 import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertNull;
@@ -140,6 +143,34 @@
         assertNull(instance.get(inhab));
     }
 
+    @Test
+    public void testOrderOfRelease() {
+        final RequestScope requestScope = new Hk2RequestScope();
+        final AtomicInteger instanceRelease = new AtomicInteger(0);
+        final Hk2RequestScope.Instance instance = requestScope.runInScope(() -> {
+            final Hk2RequestScope.Instance internalInstance = (Hk2RequestScope.Instance) requestScope.current();
+            for (int index = 1; index != 10; index++) {
+                final int in = index;
+                TestProvider testProvider = new TestProvider(String.valueOf(in)) {
+                    @Override
+                    public int hashCode() {
+                        return super.hashCode() + in;
+                    }
+                };
+                final ForeignDescriptor fd = ForeignDescriptor.wrap(testProvider, new Consumer<Object>() {
+                    @Override
+                    public void accept(Object o) {
+                        instanceRelease.set(instanceRelease.get() * 10 + in);
+                    }
+                });
+                internalInstance.put(fd, String.valueOf(index));
+            }
+            return internalInstance;
+        });
+        instance.release();
+        Assertions.assertEquals(987654321, instanceRelease.get());
+    }
+
     /**
      * Test request scope inhabitant.
      */
diff --git a/tests/e2e-server/pom.xml b/tests/e2e-server/pom.xml
index 4f5617b..3f6d2b0 100644
--- a/tests/e2e-server/pom.xml
+++ b/tests/e2e-server/pom.xml
@@ -210,6 +210,13 @@
         </dependency>
 
         <dependency>
+            <groupId>org.eclipse.jetty.ee10</groupId>
+            <artifactId>jetty-ee10-servlet</artifactId>
+            <version>${jetty.version}</version>
+            <scope>test</scope>
+        </dependency>
+
+        <dependency>
             <groupId>org.hamcrest</groupId>
             <artifactId>hamcrest</artifactId>
             <scope>test</scope>
@@ -224,6 +231,34 @@
 
     <profiles>
         <profile>
+            <id>JettyTestExclude</id>
+            <activation>
+                <jdk>[11,17)</jdk>
+            </activation>
+            <build>
+                <plugins>
+                    <plugin>
+                        <groupId>org.apache.maven.plugins</groupId>
+                        <artifactId>maven-compiler-plugin</artifactId>
+                        <executions>
+                            <execution>
+                                <id>default-testCompile</id>
+                                <phase>test-compile</phase>
+                                <configuration>
+                                    <testExcludes>
+                                        <testExclude>org/glassfish/jersey/tests/e2e/server/SimilarInputStreamTest.java</testExclude>
+                                    </testExcludes>
+                                </configuration>
+                                <goals>
+                                    <goal>testCompile</goal>
+                                </goals>
+                            </execution>
+                        </executions>
+                    </plugin>
+                </plugins>
+            </build>
+        </profile>
+        <profile>
             <id>xdk</id>
             <properties>
                 <!-- do not use security manager for xdk -->
diff --git a/tests/e2e-server/src/test/java/org/glassfish/jersey/tests/e2e/server/SimilarInputStreamTest.java b/tests/e2e-server/src/test/java/org/glassfish/jersey/tests/e2e/server/SimilarInputStreamTest.java
new file mode 100644
index 0000000..8e8b5d4
--- /dev/null
+++ b/tests/e2e-server/src/test/java/org/glassfish/jersey/tests/e2e/server/SimilarInputStreamTest.java
@@ -0,0 +1,240 @@
+/*
+ * Copyright (c) 2025 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package org.glassfish.jersey.tests.e2e.server;
+
+import org.eclipse.jetty.server.Server;
+import org.eclipse.jetty.server.ServerConnector;
+import org.eclipse.jetty.ee10.servlet.ServletContextHandler;
+import org.eclipse.jetty.ee10.servlet.ServletHolder;
+import org.glassfish.jersey.client.ClientConfig;
+import org.glassfish.jersey.internal.InternalProperties;
+import org.glassfish.jersey.jackson.JacksonFeature;
+import org.glassfish.jersey.jetty.JettyHttpContainerFactory;
+import org.glassfish.jersey.message.internal.ReaderWriter;
+import org.glassfish.jersey.server.ResourceConfig;
+import org.glassfish.jersey.servlet.ServletContainer;
+import org.glassfish.jersey.test.JerseyTest;
+import org.glassfish.jersey.test.spi.TestContainer;
+import org.glassfish.jersey.test.spi.TestContainerException;
+import org.glassfish.jersey.test.spi.TestContainerFactory;
+import org.junit.jupiter.api.Test;
+
+import jakarta.servlet.DispatcherType;
+import jakarta.servlet.Filter;
+import jakarta.servlet.FilterChain;
+import jakarta.servlet.ReadListener;
+import jakarta.servlet.ServletException;
+import jakarta.servlet.ServletInputStream;
+import jakarta.servlet.ServletRequest;
+import jakarta.servlet.ServletResponse;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletRequestWrapper;
+import jakarta.ws.rs.Consumes;
+import jakarta.ws.rs.POST;
+import jakarta.ws.rs.Path;
+import jakarta.ws.rs.Produces;
+import jakarta.ws.rs.client.Entity;
+import jakarta.ws.rs.client.Invocation;
+import jakarta.ws.rs.core.Application;
+import jakarta.ws.rs.core.MediaType;
+import jakarta.ws.rs.core.Response;
+import java.io.BufferedReader;
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.net.URI;
+import java.util.Collections;
+import java.util.EnumSet;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+public class SimilarInputStreamTest extends JerseyTest {
+
+    @Override
+    protected TestContainerFactory getTestContainerFactory() throws TestContainerException {
+        return (baseUri, deploymentContext) -> {
+            final Server server = JettyHttpContainerFactory.createServer(baseUri, false);
+            final ServerConnector connector = new ServerConnector(server);
+            connector.setPort(9001);
+            server.addConnector(connector);
+
+            final ServletContainer jerseyServletContainer = new ServletContainer(deploymentContext.getResourceConfig());
+            final ServletHolder jettyServletHolder = new ServletHolder(jerseyServletContainer);
+
+            final ServletContextHandler context = new ServletContextHandler(ServletContextHandler.NO_SESSIONS);
+            context.setContextPath("/");
+
+            // filter which will change the http servlet request to have a reply-able input stream
+            context.addFilter(FilterSettingMultiReadRequest.class,
+                    "/*", EnumSet.allOf(DispatcherType.class));
+            context.addServlet(jettyServletHolder, "/api/*");
+
+            server.setHandler(context);
+            return new TestContainer() {
+                @Override
+                public ClientConfig getClientConfig() {
+                    return new ClientConfig();
+                }
+
+                @Override
+                public URI getBaseUri() {
+                    return baseUri;
+                }
+
+                @Override
+                public void start() {
+                    try {
+                        server.start();
+                    } catch (Exception e) {
+                        throw new RuntimeException(e);
+                    }
+                }
+
+                @Override
+                public void stop() {
+                    try {
+                        server.stop();
+                    } catch (Exception e) {
+                        throw new RuntimeException(e);
+                    }
+                }
+            };
+        };
+    }
+
+    @Override
+    protected Application configure() {
+        ResourceConfig resourceConfig = new ResourceConfig(TestResource.class);
+        // force jersey to use jackson for deserialization
+        resourceConfig.addProperties(
+                Collections.singletonMap(InternalProperties.JSON_FEATURE, JacksonFeature.class.getSimpleName()));
+        return resourceConfig;
+    }
+
+    @Test
+    public void readJsonWithReplayableInputStreamFailsTest() {
+        final Invocation.Builder requestBuilder = target("/api/v1/echo").request();
+        final MyDto myDto = new MyDto();
+        myDto.setMyField("Something");
+        try (Response response = requestBuilder.post(Entity.entity(myDto, MediaType.APPLICATION_JSON))) {
+            // fixed from failure with a 400 as jackson can never finish reading the input stream
+            assertEquals(200, response.getStatus());
+            final MyDto resultDto = response.readEntity(MyDto.class);
+            assertEquals("Something", resultDto.getMyField()); //verify we still get Something
+        }
+    }
+
+    @Path("/v1")
+    public static class TestResource {
+
+        @POST
+        @Path("/echo")
+        @Produces(MediaType.APPLICATION_JSON)
+        @Consumes(MediaType.APPLICATION_JSON)
+        public MyDto echo(MyDto input) {
+            return input;
+        }
+    }
+
+    public static class MyDto {
+        private String myField;
+
+        public String getMyField() {
+            return myField;
+        }
+
+        public void setMyField(String myField) {
+            this.myField = myField;
+        }
+
+        @Override
+        public String toString() {
+            return "MyDto{"
+                    + "myField='" + myField + '\''
+                    + '}';
+        }
+    }
+
+
+    public static class FilterSettingMultiReadRequest implements Filter {
+        @Override
+        public void doFilter(ServletRequest request, ServletResponse response,
+                             FilterChain chain) throws IOException, ServletException {
+            /* wrap the request in order to read the inputstream multiple times */
+            MultiReadHttpServletRequest multiReadRequest = new MultiReadHttpServletRequest((HttpServletRequest) request);
+            chain.doFilter(multiReadRequest, response);
+        }
+    }
+
+    static class MultiReadHttpServletRequest extends HttpServletRequestWrapper {
+        private byte[] cachedBytes;
+
+        public MultiReadHttpServletRequest(HttpServletRequest request) {
+            super(request);
+        }
+
+        @Override
+        public ServletInputStream getInputStream() throws IOException {
+            if (cachedBytes == null) {
+                cacheInputStream();
+            }
+
+            return new CachedServletInputStream(cachedBytes);
+        }
+
+        @Override
+        public BufferedReader getReader() throws IOException {
+            return new BufferedReader(new InputStreamReader(getInputStream()));
+        }
+
+        private void cacheInputStream() throws IOException {
+            // Cache the inputstream in order to read it multiple times.
+            cachedBytes = ReaderWriter.readFromAsBytes(super.getInputStream());
+        }
+
+
+        /* An input stream which reads the cached request body */
+        private class CachedServletInputStream extends ServletInputStream {
+
+            private final ByteArrayInputStream buffer;
+
+            public CachedServletInputStream(byte[] contents) {
+                this.buffer = new ByteArrayInputStream(contents);
+            }
+
+            @Override
+            public int read() {
+                return buffer.read();
+            }
+
+            @Override
+            public boolean isFinished() {
+                return buffer.available() == 0;
+            }
+
+            @Override
+            public boolean isReady() {
+                return true;
+            }
+
+            @Override
+            public void setReadListener(ReadListener listener) {
+                throw new RuntimeException("Not implemented");
+            }
+        }
+    }
+}
diff --git a/tests/e2e/pom.xml b/tests/e2e/pom.xml
index 60cf525..1a6e9ff 100644
--- a/tests/e2e/pom.xml
+++ b/tests/e2e/pom.xml
@@ -175,6 +175,12 @@
             <version>${junit-platform-suite.version}</version>
             <scope>test</scope>
         </dependency>
+        <dependency>
+            <groupId>org.glassfish.jersey.media</groupId>
+            <artifactId>jersey-media-json-binding</artifactId>
+            <version>${project.version}</version>
+            <scope>test</scope>
+        </dependency>
 
         <dependency>
             <groupId>org.glassfish.jersey.test-framework</groupId>
diff --git a/tests/e2e/src/test/java/org/glassfish/jersey/tests/api/CookieImplTest.java b/tests/e2e/src/test/java/org/glassfish/jersey/tests/api/CookieImplTest.java
index 5992b54..53cd76d 100644
--- a/tests/e2e/src/test/java/org/glassfish/jersey/tests/api/CookieImplTest.java
+++ b/tests/e2e/src/test/java/org/glassfish/jersey/tests/api/CookieImplTest.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2023 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2025 Oracle and/or its affiliates. All rights reserved.
  *
  * This program and the accompanying materials are made available under the
  * terms of the Eclipse Public License v. 2.0, which is available at
@@ -151,27 +151,46 @@
     @Test
     public void testMultipleCookiesWithSameName(){
 
-        String cookieHeader = "kobe=longeststring; kobe=shortstring";
+        String cookieHeader = "kobe=oldeststring; kobe=neweststring";
         Map<String, Cookie> cookies = HttpHeaderReader.readCookies(cookieHeader);
         assertEquals(cookies.size(), 1);
         Cookie c = cookies.get("kobe");
         assertEquals(c.getVersion(), 0);
         assertEquals("kobe", c.getName());
-        assertEquals("longeststring", c.getValue());
+        assertEquals("neweststring", c.getValue());
 
-        cookieHeader = "bryant=longeststring; bryant=shortstring; fred=shortstring ;fred=longeststring;$Path=/path";
+        cookieHeader = "bryant=longeststring; bryant=neweststring; fred=oldeststring ;fred=neweststring;$Path=/path";
         cookies = HttpHeaderReader.readCookies(cookieHeader);
         assertEquals(cookies.size(), 2);
         c = cookies.get("bryant");
         assertEquals(c.getVersion(), 0);
         assertEquals("bryant", c.getName());
-        assertEquals("longeststring", c.getValue());
+        assertEquals("neweststring", c.getValue());
         c = cookies.get("fred");
         assertEquals(c.getVersion(), 0);
         assertEquals("fred", c.getName());
-        assertEquals("longeststring", c.getValue());
+        assertEquals("neweststring", c.getValue());
         assertEquals("/path", c.getPath());
 
+        cookieHeader = "cookiewithpath=longeststring;$Path=/path; cookiewithpath=string1;$Path=/path;"
+                + " cookiewithpath=string2;$Path=/path ;cookiewithpath=string3;$Path=/path";
+        cookies = HttpHeaderReader.readCookies(cookieHeader);
+        assertEquals(cookies.size(), 1);
+        c = cookies.get("cookiewithpath");
+        assertEquals(c.getVersion(), 0);
+        assertEquals("cookiewithpath", c.getName());
+        assertEquals("string3", c.getValue());
+
+        cookieHeader = "cookiewithpath=longeststring;$Path=/path/added/path; cookiewithpath=string1;$Path=/path;"
+                + " cookiewithpath=string2;$Path=/path ;cookiewithpath=string3;$Path=/path";
+        cookies = HttpHeaderReader.readCookies(cookieHeader);
+        assertEquals(cookies.size(), 1);
+        c = cookies.get("cookiewithpath");
+        assertEquals(c.getVersion(), 0);
+        assertEquals("cookiewithpath", c.getName());
+        assertEquals("longeststring", c.getValue());
+        assertEquals("/path/added/path", c.getPath());
+
     }
 
     @Test
diff --git a/tests/integration/jersey-5796/pom.xml b/tests/integration/jersey-5796/pom.xml
index 2710d8e..45a371c 100644
--- a/tests/integration/jersey-5796/pom.xml
+++ b/tests/integration/jersey-5796/pom.xml
@@ -23,7 +23,7 @@
     <parent>
         <artifactId>project</artifactId>
         <groupId>org.glassfish.jersey.tests.integration</groupId>
-        <version>2.47-SNAPSHOT</version>
+        <version>3.1.99-SNAPSHOT</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
 
diff --git a/tests/integration/jersey-5796/src/test/java/org/glassfish/jersey/tests/integration/jersey5796/Jersey5796Test.java b/tests/integration/jersey-5796/src/test/java/org/glassfish/jersey/tests/integration/jersey5796/Jersey5796Test.java
index 00705b1..80ade6a 100644
--- a/tests/integration/jersey-5796/src/test/java/org/glassfish/jersey/tests/integration/jersey5796/Jersey5796Test.java
+++ b/tests/integration/jersey-5796/src/test/java/org/glassfish/jersey/tests/integration/jersey5796/Jersey5796Test.java
@@ -18,26 +18,19 @@
 
 import static org.junit.jupiter.api.Assertions.assertEquals;
 
-import java.io.ByteArrayInputStream;
-import java.io.InputStream;
-import java.lang.ref.WeakReference;
-import java.lang.reflect.Field;
-import java.util.Map;
-import java.util.concurrent.LinkedBlockingDeque;
 import java.util.concurrent.atomic.AtomicInteger;
 
-import javax.ws.rs.GET;
-import javax.ws.rs.Path;
-import javax.ws.rs.client.Client;
-import javax.ws.rs.client.ClientBuilder;
-import javax.ws.rs.core.Application;
-import javax.ws.rs.core.GenericType;
-import javax.ws.rs.core.Response;
+import jakarta.ws.rs.GET;
+import jakarta.ws.rs.Path;
+import jakarta.ws.rs.client.Client;
+import jakarta.ws.rs.client.ClientBuilder;
+import jakarta.ws.rs.core.Application;
+import jakarta.ws.rs.core.GenericType;
+import jakarta.ws.rs.core.Response;
 
 import org.glassfish.jersey.client.ChunkedInput;
 import org.glassfish.jersey.client.ClientConfig;
 import org.glassfish.jersey.client.ClientLifecycleListener;
-import org.glassfish.jersey.client.JerseyClient;
 import org.glassfish.jersey.server.ChunkedOutput;
 import org.glassfish.jersey.server.ResourceConfig;
 import org.glassfish.jersey.test.JerseyTest;
diff --git a/tests/integration/pom.xml b/tests/integration/pom.xml
index d2ad150..b69188a 100644
--- a/tests/integration/pom.xml
+++ b/tests/integration/pom.xml
@@ -59,6 +59,7 @@
         <module>jersey-4697</module>
         <module>jersey-4722</module>
         <module>jersey-5087</module>
+        <module>jersey-5796</module>
         <module>microprofile</module>
         <module>property-check</module>
         <module>reactive-streams</module>
diff --git a/tests/integration/resteasy-client/pom.xml b/tests/integration/resteasy-client/pom.xml
index 504b4eb..97a2de8 100644
--- a/tests/integration/resteasy-client/pom.xml
+++ b/tests/integration/resteasy-client/pom.xml
@@ -28,10 +28,10 @@
         <version>3.1.99-SNAPSHOT</version>
     </parent>
 
-    <artifactId>spring-boot</artifactId>
+    <artifactId>resteasy-client</artifactId>
 
     <packaging>war</packaging>
-    <name>jersey-tests-integration-spring6</name>
+    <name>jersey-tests-integration-resteasy-client</name>
 
     <description>
         Jersey tests for Spring.Boot / Resteasy integration
@@ -41,7 +41,7 @@
         <dependency>
             <groupId>org.jboss.resteasy</groupId>
             <artifactId>resteasy-client</artifactId>
-            <version>6.2.11.Final</version>
+            <version>6.2.12.Final</version>
             <exclusions>
                 <exclusion>
                     <artifactId>commons-logging</artifactId>
@@ -72,6 +72,11 @@
             <artifactId>jersey-test-framework-provider-grizzly2</artifactId>
             <scope>test</scope>
         </dependency>
+        <dependency>
+            <groupId>org.glassfish.jersey.core</groupId>
+            <artifactId>jersey-client</artifactId>
+            <scope>test</scope>
+        </dependency>
 
         <dependency>
             <groupId>commons-logging</groupId>
diff --git a/tests/integration/resteasy-client/src/test/java/org/glassfish/jersey/tests/springboot/RestEasyClientTest.java b/tests/integration/resteasy-client/src/test/java/org/glassfish/jersey/tests/springboot/RestEasyClientTest.java
index de1461f..4848388 100644
--- a/tests/integration/resteasy-client/src/test/java/org/glassfish/jersey/tests/springboot/RestEasyClientTest.java
+++ b/tests/integration/resteasy-client/src/test/java/org/glassfish/jersey/tests/springboot/RestEasyClientTest.java
@@ -27,9 +27,12 @@
 import jakarta.ws.rs.core.MultivaluedMap;
 import jakarta.ws.rs.core.Response;
 import jakarta.ws.rs.ext.Providers;
+
 import org.glassfish.jersey.jackson.internal.DefaultJacksonJaxbJsonProvider;
 import org.glassfish.jersey.server.ResourceConfig;
 import org.glassfish.jersey.test.JerseyTest;
+import org.hamcrest.MatcherAssert;
+import org.hamcrest.Matchers;
 import org.jboss.resteasy.client.jaxrs.ResteasyClient;
 import org.jboss.resteasy.client.jaxrs.internal.ResteasyClientBuilderImpl;
 import org.junit.jupiter.api.Assertions;
@@ -40,6 +43,11 @@
 import java.lang.annotation.Annotation;
 import java.lang.reflect.Type;
 import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.atomic.AtomicReference;
+import java.util.logging.ConsoleHandler;
+import java.util.logging.Level;
+import java.util.logging.LogRecord;
+import java.util.logging.Logger;
 
 public class RestEasyClientTest extends JerseyTest {
 
@@ -62,17 +70,31 @@
 
     @Test
     public void test() throws InterruptedException {
-        try (final ResteasyClient client = new ResteasyClientBuilderImpl().build()) {
-            client.register(TestDefaultJacksonJaxbJsonProvider.class);
-
-            try (final Response r = client.target(target().getUri()).path("/test")
-                    .request().post(Entity.entity("{\"test\": \"test\"}", MediaType.APPLICATION_JSON))) {
-                Object o = r.readEntity(Object.class);
-                Assertions.assertTrue(o.toString().contains("test"));
-                readFromLatch.await();
-                Assertions.assertEquals(0, readFromLatch.getCount(), "DefaultJacksonJaxbJsonProvider has not been used");
+        AtomicReference<String> messageRef = new AtomicReference<>();
+        Logger logger = Logger.getLogger(DefaultJacksonJaxbJsonProvider.class.getName());
+        logger.addHandler(new ConsoleHandler() {
+            @Override
+            public void publish(LogRecord record) {
+                messageRef.set(record.getMessage());
             }
+        });
+        logger.setLevel(Level.FINE);
+
+        final ResteasyClient client = new ResteasyClientBuilderImpl().build();
+
+        client.register(TestDefaultJacksonJaxbJsonProvider.class);
+
+        try (final Response r = client.target(target().getUri()).path("/test")
+                .request().post(Entity.entity("{\"test\": \"test\"}", MediaType.APPLICATION_JSON))) {
+            Object o = r.readEntity(Object.class);
+            Assertions.assertTrue(o.toString().contains("test"));
+            readFromLatch.await();
+            Assertions.assertEquals(0, readFromLatch.getCount(), "DefaultJacksonJaxbJsonProvider has not been used");
         }
+
+        client.close();
+        MatcherAssert.assertThat(messageRef.get(), Matchers.notNullValue());
+
     }
 
     public static class TestDefaultJacksonJaxbJsonProvider extends DefaultJacksonJaxbJsonProvider {
diff --git a/tests/integration/security-digest/pom.xml b/tests/integration/security-digest/pom.xml
index 276d18a..c378737 100644
--- a/tests/integration/security-digest/pom.xml
+++ b/tests/integration/security-digest/pom.xml
@@ -69,7 +69,7 @@
                     <loginServices>
                         <loginService implementation="org.eclipse.jetty.security.HashLoginService">
                             <name>my-realm</name>
-                            <config implementation="org.eclipse.jetty.ee10.maven.plugin.MavenResource">
+                            <config implementation="org.eclipse.jetty.maven.MavenResource">
                                 <resourceAsString>${basedir}/src/main/resources/jetty/realm.properties</resourceAsString>
                             </config>
                         </loginService>
diff --git a/tools/jersey-release-notes-maven-plugin/pom.xml b/tools/jersey-release-notes-maven-plugin/pom.xml
index 1522089..dfd342b 100644
--- a/tools/jersey-release-notes-maven-plugin/pom.xml
+++ b/tools/jersey-release-notes-maven-plugin/pom.xml
@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <!--
 
-    Copyright (c) 2019, 2024 Oracle and/or its affiliates. All rights reserved.
+    Copyright (c) 2019, 2025 Oracle and/or its affiliates. All rights reserved.
 
     This program and the accompanying materials are made available under the
     terms of the Eclipse Public License v. 2.0, which is available at
@@ -56,7 +56,7 @@
         <dependency>
             <groupId>org.apache.maven.plugin-tools</groupId>
             <artifactId>maven-plugin-annotations</artifactId>
-            <version>3.6.0</version>
+            <version>3.15.1</version>
             <scope>provided</scope>
         </dependency>
         <dependency>
@@ -74,7 +74,8 @@
         <dependency>
             <groupId>commons-io</groupId>
             <artifactId>commons-io</artifactId>
-            <version>2.17.0</version>
+            <version>${commons.io.version}</version>
+            <scope>test</scope>
         </dependency>
         <dependency>
             <groupId>org.apache.maven</groupId>
@@ -83,9 +84,15 @@
             <scope>test</scope>
         </dependency>
         <dependency>
-            <groupId>junit</groupId>
-            <artifactId>junit</artifactId>
-            <version>4.13.2</version>
+            <groupId>org.junit.jupiter</groupId>
+            <artifactId>junit-jupiter-api</artifactId>
+            <version>${junit.version}</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.junit.jupiter</groupId>
+            <artifactId>junit-jupiter</artifactId>
+            <version>${junit.version}</version>
             <scope>test</scope>
         </dependency>
 
@@ -96,7 +103,7 @@
             <plugin>
                 <groupId>org.apache.maven.plugins</groupId>
                 <artifactId>maven-plugin-plugin</artifactId>
-                <version>3.6.0</version>
+                <version>3.15.1</version>
                 <configuration>
                     <skipErrorNoDescriptorsFound>true</skipErrorNoDescriptorsFound>
                 </configuration>
@@ -113,7 +120,7 @@
             <plugin>
                 <groupId>org.apache.maven.plugins</groupId>
                 <artifactId>maven-compiler-plugin</artifactId>
-                <version>3.1</version>
+                <version>3.14.0</version>
                 <inherited>true</inherited>
                 <configuration>
                     <source>${java.version}</source>
@@ -127,6 +134,8 @@
 
     <properties>
         <java.version>1.8</java.version>
-        <maven.version>3.8.1</maven.version>
+        <maven.version>3.9.9</maven.version>
+        <commons.io.version>2.19.0</commons.io.version>
+        <junit.version>5.12.2</junit.version>
     </properties>
 </project>
diff --git a/tools/jersey-release-notes-maven-plugin/src/test/java/org/glassfish/jersey/tools/plugins/releasenotes/GenerateReleaseNotesMojoTest.java b/tools/jersey-release-notes-maven-plugin/src/test/java/org/glassfish/jersey/tools/plugins/releasenotes/GenerateReleaseNotesMojoTest.java
index 93287ee..1826730 100644
--- a/tools/jersey-release-notes-maven-plugin/src/test/java/org/glassfish/jersey/tools/plugins/releasenotes/GenerateReleaseNotesMojoTest.java
+++ b/tools/jersey-release-notes-maven-plugin/src/test/java/org/glassfish/jersey/tools/plugins/releasenotes/GenerateReleaseNotesMojoTest.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2019 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2019, 2025 Oracle and/or its affiliates. All rights reserved.
  *
  * This program and the accompanying materials are made available under the
  * terms of the Eclipse Public License v. 2.0, which is available at
@@ -23,17 +23,14 @@
 import org.apache.maven.project.ProjectBuilder;
 import org.apache.maven.project.ProjectBuildingRequest;
 import org.eclipse.aether.DefaultRepositorySystemSession;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
 
 import java.io.File;
 
-@RunWith(JUnit4.class)
 public class GenerateReleaseNotesMojoTest extends AbstractMojoTestCase {
 
-    @Before
+    @BeforeEach
     public void setUp() throws Exception {
 
         // required for mojo lookups to work