Merge pull request #5079 from senivam/3x_merged

update the 3.x branch with actual master
diff --git a/NOTICE.md b/NOTICE.md
index 0846b57..5533ac7 100644
--- a/NOTICE.md
+++ b/NOTICE.md
@@ -70,10 +70,10 @@
 * Project: http://www.javassist.org/

 * Copyright (C) 1999- Shigeru Chiba. All Rights Reserved.

 

-Jackson JAX-RS Providers Version 2.11.3

+Jackson JAX-RS Providers Version 2.13.3

 * License: Apache License, 2.0

 * Project: https://github.com/FasterXML/jackson-jaxrs-providers

-* Copyright: (c) 2009-2011 FasterXML, LLC. All rights reserved unless otherwise indicated.

+* Copyright: (c) 2009-2022 FasterXML, LLC. All rights reserved unless otherwise indicated.

 

 jQuery v1.12.4

 * License: jquery.org/license

@@ -95,7 +95,7 @@
 * Project: http://www.kineticjs.com, https://github.com/ericdrowell/KineticJS

 * Copyright: Eric Rowell

 

-org.objectweb.asm Version 9.0

+org.objectweb.asm Version 9.3

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

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

 

diff --git a/connectors/jetty-connector/src/test/java/org/glassfish/jersey/jetty/connector/ProxyTest.java b/connectors/jetty-connector/src/test/java/org/glassfish/jersey/jetty/connector/ProxyTest.java
deleted file mode 100644
index baebc78..0000000
--- a/connectors/jetty-connector/src/test/java/org/glassfish/jersey/jetty/connector/ProxyTest.java
+++ /dev/null
@@ -1,147 +0,0 @@
-/*
- * Copyright (c) 2020, 2021 Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2019 Banco do Brasil S/A. 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.jetty.connector;
-
-import org.eclipse.jetty.server.Request;
-import org.eclipse.jetty.server.Server;
-import org.eclipse.jetty.server.handler.AbstractHandler;
-import org.glassfish.jersey.client.ClientConfig;
-import org.glassfish.jersey.client.ClientProperties;
-import org.glassfish.jersey.server.ResourceConfig;
-import org.glassfish.jersey.test.JerseyTest;
-import org.junit.Test;
-
-import jakarta.servlet.ServletException;
-import jakarta.servlet.http.HttpServletRequest;
-import jakarta.servlet.http.HttpServletResponse;
-import jakarta.ws.rs.GET;
-import jakarta.ws.rs.Path;
-import jakarta.ws.rs.core.Application;
-import jakarta.ws.rs.core.Response;
-import java.io.IOException;
-import java.nio.charset.Charset;
-import java.util.Base64;
-
-import static org.junit.Assert.assertEquals;
-
-/**
- * @author Marcelo Rubim
-\ */
-public class ProxyTest extends JerseyTest {
-    private static final Charset CHARACTER_SET = Charset.forName("iso-8859-1");
-    private static final String PROXY_URI = "http://127.0.0.1:9997";
-    private static final String PROXY_USERNAME = "proxy-user";
-    private static final String PROXY_PASSWORD = "proxy-password";
-
-
-    @Path("")
-    public static class ProxyResource {
-
-        @GET
-        public Response getProxy() {
-            return Response.status(407).header("Proxy-Authenticate", "Basic").build();
-        }
-
-    }
-
-    @Path("proxyTest")
-    public static class ProxyTestResource {
-
-        @GET
-        public Response getOK() {
-            return Response.ok().build();
-        }
-
-    }
-
-    @Override
-    protected Application configure() {
-        ResourceConfig config = new ResourceConfig(ProxyResource.class, ProxyTestResource.class);
-        return config;
-    }
-
-    @Override
-    protected void configureClient(ClientConfig config) {
-        config.connectorProvider(new JettyConnectorProvider());
-    }
-
-    @Test
-    public void testGet407() {
-        startFakeProxy();
-        client().property(ClientProperties.PROXY_URI, ProxyTest.PROXY_URI);
-        Response response = target("proxyTest").request().get();
-        assertEquals(407, response.getStatus());
-    }
-
-    @Test
-    public void testGetSuccess() {
-        startFakeProxy();
-        client().property(ClientProperties.PROXY_URI, ProxyTest.PROXY_URI);
-        client().property(ClientProperties.PROXY_USERNAME, ProxyTest.PROXY_USERNAME);
-        client().property(ClientProperties.PROXY_PASSWORD, ProxyTest.PROXY_PASSWORD);
-        Response response = target("proxyTest").request().get();
-        assertEquals(200, response.getStatus());
-    }
-
-    private void startFakeProxy(){
-        Server server = new Server(9997);
-        server.setHandler(new ProxyHandler());
-        try {
-            server.start();
-        } catch (Exception e) {
-
-        }
-    }
-
-    class ProxyHandler extends AbstractHandler {
-        @Override
-        public void handle(String target,
-                           Request baseRequest,
-                           HttpServletRequest request,
-                           HttpServletResponse response) throws IOException,
-                ServletException {
-
-            if (request.getHeader("Proxy-Authorization") != null) {
-                String proxyAuthorization = request.getHeader("Proxy-Authorization");
-                String decoded = new String(Base64.getDecoder().decode(proxyAuthorization.substring(6).getBytes()),
-                        CHARACTER_SET);
-                final String[] split = decoded.split(":");
-                final String username = split[0];
-                final String password = split[1];
-
-                if (!username.equals(PROXY_USERNAME)) {
-                    response.setStatus(400);
-                    System.out.println("Found unexpected username: " + username);
-                }
-
-                if (!password.equals(PROXY_PASSWORD)) {
-                    response.setStatus(400);
-                    System.out.println("Found unexpected password: " + username);
-                }
-                response.setStatus(200);
-                //TODO Add redirect to requestURI
-            } else {
-                response.setStatus(407);
-                response.addHeader("Proxy-Authenticate", "Basic");
-            }
-
-
-            baseRequest.setHandled(true);
-        }
-    }
-}
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 176fcb3..71f38ea 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
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, 2020 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2022 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
@@ -19,15 +19,20 @@
 import java.io.ByteArrayInputStream;
 import java.io.IOException;
 import java.io.InputStream;
+import java.net.URI;
 import java.util.Map;
+import java.util.Set;
 import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.TimeoutException;
 
+import jakarta.ws.rs.core.HttpHeaders;
 import jakarta.ws.rs.core.Response;
 
+import org.glassfish.jersey.client.ClientProperties;
 import org.glassfish.jersey.client.ClientRequest;
 import org.glassfish.jersey.client.ClientResponse;
 import org.glassfish.jersey.netty.connector.internal.NettyInputStream;
+import org.glassfish.jersey.netty.connector.internal.RedirectException;
 
 import io.netty.buffer.ByteBuf;
 import io.netty.channel.ChannelHandlerContext;
@@ -36,6 +41,7 @@
 import io.netty.handler.codec.http.HttpHeaderNames;
 import io.netty.handler.codec.http.HttpObject;
 import io.netty.handler.codec.http.HttpResponse;
+import io.netty.handler.codec.http.HttpResponseStatus;
 import io.netty.handler.codec.http.HttpUtil;
 import io.netty.handler.codec.http.LastHttpContent;
 import io.netty.handler.timeout.IdleStateEvent;
@@ -47,21 +53,32 @@
  */
 class JerseyClientHandler extends SimpleChannelInboundHandler<HttpObject> {
 
+    private static final int DEFAULT_MAX_REDIRECTS = 5;
+
+    // Modified only by the same thread. No need to synchronize it.
+    private final Set<URI> redirectUriHistory;
     private final ClientRequest jerseyRequest;
     private final CompletableFuture<ClientResponse> responseAvailable;
     private final CompletableFuture<?> responseDone;
+    private final boolean followRedirects;
+    private final int maxRedirects;
+    private final NettyConnector connector;
 
     private NettyInputStream nis;
     private ClientResponse jerseyResponse;
 
     private boolean readTimedOut;
 
-    JerseyClientHandler(ClientRequest request,
-                        CompletableFuture<ClientResponse> responseAvailable,
-                        CompletableFuture<?> responseDone) {
+    JerseyClientHandler(ClientRequest request, CompletableFuture<ClientResponse> responseAvailable,
+                        CompletableFuture<?> responseDone, Set<URI> redirectUriHistory, NettyConnector connector) {
+        this.redirectUriHistory = redirectUriHistory;
         this.jerseyRequest = request;
         this.responseAvailable = responseAvailable;
         this.responseDone = responseDone;
+        // Follow redirects by default
+        this.followRedirects = jerseyRequest.resolveProperty(ClientProperties.FOLLOW_REDIRECTS, true);
+        this.maxRedirects = jerseyRequest.resolveProperty(NettyClientProperties.MAX_REDIRECTS, DEFAULT_MAX_REDIRECTS);
+        this.connector = connector;
     }
 
     @Override
@@ -84,7 +101,41 @@
        if (jerseyResponse != null) {
           ClientResponse cr = jerseyResponse;
           jerseyResponse = null;
-          responseAvailable.complete(cr);
+          int responseStatus = cr.getStatus();
+          if (followRedirects
+                  && (responseStatus == HttpResponseStatus.MOVED_PERMANENTLY.code()
+                          || responseStatus == HttpResponseStatus.FOUND.code()
+                          || responseStatus == HttpResponseStatus.SEE_OTHER.code()
+                          || responseStatus == HttpResponseStatus.TEMPORARY_REDIRECT.code()
+                          || responseStatus == HttpResponseStatus.PERMANENT_REDIRECT.code())) {
+              String location = cr.getHeaderString(HttpHeaders.LOCATION);
+              if (location == null || location.isEmpty()) {
+                  responseAvailable.completeExceptionally(new RedirectException(LocalizationMessages.REDIRECT_NO_LOCATION()));
+              } else {
+                  try {
+                      URI newUri = URI.create(location);
+                      boolean alreadyRequested = !redirectUriHistory.add(newUri);
+                      if (alreadyRequested) {
+                          // infinite loop detection
+                          responseAvailable.completeExceptionally(
+                                  new RedirectException(LocalizationMessages.REDIRECT_INFINITE_LOOP()));
+                      } else if (redirectUriHistory.size() > maxRedirects) {
+                          // maximal number of redirection
+                          responseAvailable.completeExceptionally(
+                                  new RedirectException(LocalizationMessages.REDIRECT_LIMIT_REACHED(maxRedirects)));
+                      } else {
+                          ClientRequest newReq = new ClientRequest(jerseyRequest);
+                          newReq.setUri(newUri);
+                          connector.execute(newReq, redirectUriHistory, responseAvailable);
+                      }
+                  } catch (IllegalArgumentException e) {
+                      responseAvailable.completeExceptionally(
+                              new RedirectException(LocalizationMessages.REDIRECT_ERROR_DETERMINING_LOCATION(location)));
+                  }
+              }
+          } else {
+              responseAvailable.complete(cr);
+          }
        }
     }
 
@@ -92,7 +143,6 @@
     public void channelRead0(ChannelHandlerContext ctx, HttpObject msg) {
         if (msg instanceof HttpResponse) {
             final HttpResponse response = (HttpResponse) msg;
-
             jerseyResponse = new ClientResponse(new Response.StatusType() {
                 @Override
                 public int getStatusCode() {
diff --git a/connectors/netty-connector/src/main/java/org/glassfish/jersey/netty/connector/NettyClientProperties.java b/connectors/netty-connector/src/main/java/org/glassfish/jersey/netty/connector/NettyClientProperties.java
index bf34699..671b08f 100644
--- a/connectors/netty-connector/src/main/java/org/glassfish/jersey/netty/connector/NettyClientProperties.java
+++ b/connectors/netty-connector/src/main/java/org/glassfish/jersey/netty/connector/NettyClientProperties.java
@@ -68,4 +68,18 @@
      * @see javax.net.ssl.SSLParameters#setEndpointIdentificationAlgorithm(String)
      */
     public static final String ENABLE_SSL_HOSTNAME_VERIFICATION = "jersey.config.client.tls.enableHostnameVerification";
+
+    /**
+     * The maximal number of redirects during single request.
+     * <p/>
+     * Value is expected to be positive {@link Integer}. Default value is {@value #DEFAULT_MAX_REDIRECTS}.
+     * <p/>
+     * HTTP redirection must be enabled by property {@link org.glassfish.jersey.client.ClientProperties#FOLLOW_REDIRECTS},
+     * otherwise {@code MAX_REDIRECTS} is not applied.
+     *
+     * @since 2.36
+     * @see org.glassfish.jersey.client.ClientProperties#FOLLOW_REDIRECTS
+     * @see org.glassfish.jersey.netty.connector.internal.RedirectException
+     */
+    public static final String MAX_REDIRECTS = "jersey.config.client.NettyConnectorProvider.maxRedirects";
 }
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 3e931f0..77d0d27 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
@@ -19,12 +19,17 @@
 import java.io.IOException;
 import java.io.OutputStream;
 import java.net.InetSocketAddress;
+import java.net.Proxy;
+import java.net.ProxySelector;
+import java.net.SocketAddress;
 import java.net.URI;
 import java.util.ArrayList;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.NoSuchElementException;
+import java.util.Set;
 import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.CompletionException;
 import java.util.concurrent.ExecutorService;
@@ -43,6 +48,7 @@
 import io.netty.channel.Channel;
 import io.netty.channel.ChannelDuplexHandler;
 import io.netty.channel.ChannelHandlerContext;
+import io.netty.channel.ChannelInboundHandlerAdapter;
 import io.netty.channel.ChannelInitializer;
 import io.netty.channel.ChannelOption;
 import io.netty.channel.ChannelPipeline;
@@ -51,16 +57,20 @@
 import io.netty.channel.socket.SocketChannel;
 import io.netty.channel.socket.nio.NioSocketChannel;
 import io.netty.handler.codec.http.DefaultFullHttpRequest;
+import io.netty.handler.codec.http.DefaultHttpHeaders;
 import io.netty.handler.codec.http.DefaultHttpRequest;
 import io.netty.handler.codec.http.HttpChunkedInput;
 import io.netty.handler.codec.http.HttpClientCodec;
 import io.netty.handler.codec.http.HttpContentDecompressor;
 import io.netty.handler.codec.http.HttpHeaderNames;
+import io.netty.handler.codec.http.HttpHeaders;
 import io.netty.handler.codec.http.HttpMethod;
 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.proxy.HttpProxyHandler;
+import io.netty.handler.proxy.ProxyConnectionEvent;
+import io.netty.handler.proxy.ProxyHandler;
 import io.netty.handler.ssl.ApplicationProtocolConfig;
 import io.netty.handler.ssl.ClientAuth;
 import io.netty.handler.ssl.IdentityCipherSuiteFilter;
@@ -151,7 +161,9 @@
     @Override
     public ClientResponse apply(ClientRequest jerseyRequest) {
         try {
-            return execute(jerseyRequest).join();
+            CompletableFuture<ClientResponse> response = new CompletableFuture<>();
+            execute(jerseyRequest, new HashSet<>(), response);
+            return response.join();
         } catch (CompletionException cex) {
             final Throwable t = cex.getCause() == null ? cex : cex.getCause();
             throw new ProcessingException(t.getMessage(), t);
@@ -162,19 +174,25 @@
 
     @Override
     public Future<?> apply(final ClientRequest jerseyRequest, final AsyncConnectorCallback jerseyCallback) {
-        return execute(jerseyRequest).whenCompleteAsync((r, th) -> {
-                  if (th == null) jerseyCallback.response(r);
-                  else jerseyCallback.failure(th);
-               }, executorService);
+        CompletableFuture<ClientResponse> response = new CompletableFuture<>();
+        response.whenCompleteAsync((r, th) -> {
+            if (th == null) {
+                jerseyCallback.response(r);
+            } else {
+                jerseyCallback.failure(th);
+            }
+        }, executorService);
+        execute(jerseyRequest, new HashSet<>(), response);
+        return response;
     }
 
-    protected CompletableFuture<ClientResponse> execute(final ClientRequest jerseyRequest) {
+    protected void execute(final ClientRequest jerseyRequest, final Set<URI> redirectUriHistory,
+            final CompletableFuture<ClientResponse> responseAvailable) {
         Integer timeout = jerseyRequest.resolveProperty(ClientProperties.READ_TIMEOUT, 0);
         if (timeout == null || timeout < 0) {
             throw new ProcessingException(LocalizationMessages.WRONG_READ_TIMEOUT(timeout));
         }
 
-        final CompletableFuture<ClientResponse> responseAvailable = new CompletableFuture<>();
         final CompletableFuture<?> responseDone = new CompletableFuture<>();
 
         final URI requestUri = jerseyRequest.getUri();
@@ -213,6 +231,8 @@
                }
             }
 
+            Integer connectTimeout = jerseyRequest.resolveProperty(ClientProperties.CONNECT_TIMEOUT, 0);
+
             if (chan == null) {
                Bootstrap b = new Bootstrap();
                b.group(group)
@@ -236,8 +256,29 @@
 
                          InetSocketAddress proxyAddr = new InetSocketAddress(u.getHost(),
                                                                              u.getPort() == -1 ? 8080 : u.getPort());
-                         p.addLast(userName == null ? new HttpProxyHandler(proxyAddr)
-                                                    : new HttpProxyHandler(proxyAddr, userName, password));
+                         ProxyHandler proxy = createProxyHandler(jerseyRequest, proxyAddr, userName, password, connectTimeout);
+                         p.addLast(proxy);
+                     } else {
+                         ProxySelector sel = ProxySelector.getDefault();
+                         for (Proxy proxy: sel.select(requestUri)) {
+                             if (Proxy.Type.HTTP.equals(proxy.type())) {
+                                 SocketAddress proxyAddress = proxy.address();
+                                 if (InetSocketAddress.class.isInstance(proxy.address())) {
+                                     InetSocketAddress proxyAddr = (InetSocketAddress) proxyAddress;
+                                     if (proxyAddr.isUnresolved()
+                                             && proxyAddr.getHostName() != null
+                                             && proxyAddr.getHostName().startsWith("http://")) {
+                                         proxyAddress = new InetSocketAddress(
+                                                 proxyAddr.getHostString().substring(7), proxyAddr.getPort()
+                                         );
+                                     }
+                                 }
+                                 ProxyHandler proxyHandler
+                                         = createProxyHandler(jerseyRequest, proxyAddress, null, null, connectTimeout);
+                                 p.addLast(proxyHandler);
+                                 break;
+                             }
+                         }
                      }
 
                      // Enable HTTPS if necessary.
@@ -274,7 +315,6 @@
                 });
 
                // connect timeout
-               Integer connectTimeout = jerseyRequest.resolveProperty(ClientProperties.CONNECT_TIMEOUT, 0);
                if (connectTimeout > 0) {
                    b.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, connectTimeout);
                }
@@ -290,7 +330,8 @@
             // assert: it is ok to abort the entire response, if responseDone is completed exceptionally - in particular, nothing
             //         will leak
             final Channel ch = chan;
-            JerseyClientHandler clientHandler = new JerseyClientHandler(jerseyRequest, responseAvailable, responseDone);
+            JerseyClientHandler clientHandler =
+                    new JerseyClientHandler(jerseyRequest, responseAvailable, responseDone, redirectUriHistory, this);
             // read timeout makes sense really as an inactivity timeout
             ch.pipeline().addLast(READ_TIMEOUT_HANDLER,
                                   new IdleStateHandler(0, 0, timeout, TimeUnit.MILLISECONDS));
@@ -346,9 +387,7 @@
             }
 
             // headers
-            for (final Map.Entry<String, List<String>> e : jerseyRequest.getStringHeaders().entrySet()) {
-                nettyRequest.headers().add(e.getKey(), e.getValue());
-            }
+            setHeaders(jerseyRequest, nettyRequest.headers());
 
             // host header - http 1.1
             nettyRequest.headers().add(HttpHeaderNames.HOST, jerseyRequest.getUri().getHost());
@@ -411,8 +450,6 @@
         } catch (InterruptedException e) {
             responseDone.completeExceptionally(e);
         }
-
-        return responseAvailable;
     }
 
     private String buildPathWithQueryParameters(URI requestUri) {
@@ -475,4 +512,24 @@
           }
        }
     }
+
+    private static ProxyHandler createProxyHandler(ClientRequest jerseyRequest, SocketAddress proxyAddr,
+                                                   String userName, String password, long connectTimeout) {
+        HttpHeaders httpHeaders = setHeaders(jerseyRequest, new DefaultHttpHeaders());
+
+        ProxyHandler proxy = userName == null ? new HttpProxyHandler(proxyAddr, httpHeaders)
+                : new HttpProxyHandler(proxyAddr, userName, password, httpHeaders);
+        if (connectTimeout > 0) {
+            proxy.setConnectTimeoutMillis(connectTimeout);
+        }
+
+        return proxy;
+    }
+
+    private static HttpHeaders setHeaders(ClientRequest jerseyRequest, HttpHeaders headers) {
+        for (final Map.Entry<String, List<String>> e : jerseyRequest.getStringHeaders().entrySet()) {
+            headers.add(e.getKey(), e.getValue());
+        }
+        return headers;
+    }
 }
diff --git a/connectors/netty-connector/src/main/java/org/glassfish/jersey/netty/connector/internal/RedirectException.java b/connectors/netty-connector/src/main/java/org/glassfish/jersey/netty/connector/internal/RedirectException.java
new file mode 100644
index 0000000..bef04e1
--- /dev/null
+++ b/connectors/netty-connector/src/main/java/org/glassfish/jersey/netty/connector/internal/RedirectException.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2022 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.netty.connector.internal;
+
+import org.glassfish.jersey.client.ClientProperties;
+
+/**
+ * This Exception is used only if {@link ClientProperties#FOLLOW_REDIRECTS} is set to {@code true}.
+ * <p/>
+ * This exception is thrown when any of the Redirect HTTP response status codes (301, 302, 303, 307, 308) is received and:
+ * <ul>
+ * <li>
+ * the chained redirection count exceeds the value of
+ * {@link org.glassfish.jersey.netty.connector.NettyClientProperties#MAX_REDIRECTS}
+ * </li>
+ * <li>
+ * or an infinite redirection loop is detected
+ * </li>
+ * <li>
+ * or Location response header is missing, empty or does not contain a valid {@link java.net.URI}.
+ * </li>
+ * </ul>
+ *
+ */
+public class RedirectException extends Exception {
+
+    private static final long serialVersionUID = 4357724300486801294L;
+
+    /**
+     * Constructor.
+     *
+     * @param message the detail message. The detail message is saved for
+     *                later retrieval by the {@link #getMessage()} method.
+     */
+    public RedirectException(String message) {
+        super(message);
+    }
+
+    /**
+     * Constructor.
+     *
+     * @param message the detail message. The detail message is saved for
+     *                later retrieval by the {@link #getMessage()} method.
+     */
+    public RedirectException(String message, Throwable t) {
+        super(message, t);
+    }
+}
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 bf12db6..9055d62 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, 2021 Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2016, 2022 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
@@ -19,4 +19,7 @@
 wrong.max.pool.size=Unexpected ("{0}") maximum number of connections per destination.
 wrong.max.pool.total=Unexpected ("{0}") maximum number of connections total.
 wrong.max.pool.idle=Unexpected ("{0}") maximum number of idle seconds.
-
+redirect.no.location="Received redirect that does not contain a location or the location is empty."
+redirect.error.determining.location="Error determining redirect location: ({0})."
+redirect.infinite.loop="Infinite loop in chained redirects detected."
+redirect.limit.reached="Max chained redirect limit ({0}) exceeded."
diff --git a/connectors/netty-connector/src/test/java/org/glassfish/jersey/netty/connector/FollowRedirectsTest.java b/connectors/netty-connector/src/test/java/org/glassfish/jersey/netty/connector/FollowRedirectsTest.java
new file mode 100644
index 0000000..6eb2d93
--- /dev/null
+++ b/connectors/netty-connector/src/test/java/org/glassfish/jersey/netty/connector/FollowRedirectsTest.java
@@ -0,0 +1,163 @@
+/*
+ * Copyright (c) 2022 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.netty.connector;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+
+import java.net.URI;
+import java.util.logging.Logger;
+
+import jakarta.ws.rs.GET;
+import jakarta.ws.rs.Path;
+import jakarta.ws.rs.ProcessingException;
+import jakarta.ws.rs.client.Client;
+import jakarta.ws.rs.client.ClientBuilder;
+import jakarta.ws.rs.client.WebTarget;
+import jakarta.ws.rs.core.Application;
+import jakarta.ws.rs.core.Response;
+
+import org.glassfish.jersey.client.ClientConfig;
+import org.glassfish.jersey.client.ClientProperties;
+import org.glassfish.jersey.logging.LoggingFeature;
+import org.glassfish.jersey.netty.connector.internal.RedirectException;
+import org.glassfish.jersey.server.ResourceConfig;
+import org.glassfish.jersey.test.JerseyTest;
+import org.junit.Test;
+
+public class FollowRedirectsTest extends JerseyTest {
+
+    private static final Logger LOGGER = Logger.getLogger(FollowRedirectsTest.class.getName());
+    private static final String TEST_URL = "http://localhost:9998/test";
+
+    @Path("/test")
+    public static class RedirectResource {
+        @GET
+        public String get() {
+            return "GET";
+        }
+
+        @GET
+        @Path("redirect")
+        public Response redirect() {
+            return Response.seeOther(URI.create(TEST_URL)).build();
+        }
+
+        @GET
+        @Path("loop")
+        public Response loop() {
+            return Response.seeOther(URI.create(TEST_URL + "/loop")).build();
+        }
+
+        @GET
+        @Path("redirect2")
+        public Response redirect2() {
+            return Response.seeOther(URI.create(TEST_URL + "/redirect")).build();
+        }
+    }
+
+    @Override
+    protected Application configure() {
+        ResourceConfig config = new ResourceConfig(RedirectResource.class);
+        config.register(new LoggingFeature(LOGGER, LoggingFeature.Verbosity.PAYLOAD_ANY));
+        return config;
+    }
+
+    @Override
+    protected void configureClient(ClientConfig config) {
+        config.property(ClientProperties.FOLLOW_REDIRECTS, false);
+        config.connectorProvider(new NettyConnectorProvider());
+    }
+
+    @Test
+    public void testDoFollow() {
+        final URI u = target().getUri();
+        ClientConfig config = new ClientConfig().property(ClientProperties.FOLLOW_REDIRECTS, true);
+        config.connectorProvider(new NettyConnectorProvider());
+        Client c = ClientBuilder.newClient(config);
+        WebTarget t = c.target(u);
+        Response r = t.path("test/redirect")
+                .request().get();
+        assertEquals(200, r.getStatus());
+        assertEquals("GET", r.readEntity(String.class));
+        c.close();
+    }
+
+    @Test
+    public void testDoFollowPerRequestOverride() {
+        WebTarget t = target("test/redirect");
+        t.property(ClientProperties.FOLLOW_REDIRECTS, true);
+        Response r = t.request().get();
+        assertEquals(200, r.getStatus());
+        assertEquals("GET", r.readEntity(String.class));
+    }
+
+    @Test
+    public void testDontFollow() {
+        WebTarget t = target("test/redirect");
+        assertEquals(303, t.request().get().getStatus());
+    }
+
+    @Test
+    public void testDontFollowPerRequestOverride() {
+        final URI u = target().getUri();
+        ClientConfig config = new ClientConfig().property(ClientProperties.FOLLOW_REDIRECTS, true);
+        config.connectorProvider(new NettyConnectorProvider());
+        Client client = ClientBuilder.newClient(config);
+        WebTarget t = client.target(u);
+        t.property(ClientProperties.FOLLOW_REDIRECTS, false);
+        Response r = t.path("test/redirect").request().get();
+        assertEquals(303, r.getStatus());
+        client.close();
+    }
+
+    @Test
+    public void testInfiniteLoop() {
+        WebTarget t = target("test/loop");
+        t.property(ClientProperties.FOLLOW_REDIRECTS, true);
+        try {
+            t.request().get();
+            fail("Expected exception");
+        } catch (ProcessingException e) {
+            assertEquals(RedirectException.class, e.getCause().getClass());
+            assertEquals(LocalizationMessages.REDIRECT_INFINITE_LOOP(), e.getCause().getMessage());
+        }
+    }
+
+    @Test
+    public void testRedirectLimitReached() {
+        WebTarget t = target("test/redirect2");
+        t.property(ClientProperties.FOLLOW_REDIRECTS, true);
+        t.property(NettyClientProperties.MAX_REDIRECTS, 1);
+        try {
+            t.request().get();
+            fail("Expected exception");
+        } catch (ProcessingException e) {
+            assertEquals(RedirectException.class, e.getCause().getClass());
+            assertEquals(LocalizationMessages.REDIRECT_LIMIT_REACHED(1), e.getCause().getMessage());
+        }
+    }
+
+    @Test
+    public void testRedirectNoLimitReached() {
+        WebTarget t = target("test/redirect2");
+        t.property(ClientProperties.FOLLOW_REDIRECTS, true);
+        Response r = t.request().get();
+        assertEquals(200, r.getStatus());
+        assertEquals("GET", r.readEntity(String.class));
+    }
+}
diff --git a/core-common/src/main/java/org/glassfish/jersey/CommonProperties.java b/core-common/src/main/java/org/glassfish/jersey/CommonProperties.java
index 6b2021d..d5a1658 100644
--- a/core-common/src/main/java/org/glassfish/jersey/CommonProperties.java
+++ b/core-common/src/main/java/org/glassfish/jersey/CommonProperties.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2021 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2022 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
@@ -256,6 +256,55 @@
     public static final String JAXRS_SERVICE_LOADING_ENABLE = "jakarta.ws.rs.loadServices";
 
     /**
+     * Comma separated list of jackson modules which are only enabled (only those modules will be used)
+     * for json-jackson processing
+     *
+     * @since 2.36
+     */
+    public static final String JSON_JACKSON_ENABLED_MODULES = "jersey.config.json.jackson.enabled.modules";
+
+    /**
+     * Client-specific version of {@link CommonProperties#JSON_JACKSON_ENABLED_MODULES}.
+     *
+     * If present, it overrides the generic one for the client environment.
+     * @since 2.36
+     */
+    public static final String JSON_JACKSON_ENABLED_MODULES_CLIENT = "jersey.config.client.json.jackson.enabled.modules";
+
+    /**
+     * Server-specific version of {@link CommonProperties#JSON_JACKSON_ENABLED_MODULES}.
+     *
+     * If present, it overrides the generic one for the server environment.
+     * @since 2.36
+     */
+    public static final String JSON_JACKSON_ENABLED_MODULES_SERVER = "jersey.config.server.json.jackson.enabled.modules";
+
+    /**
+     * Comma separated list of jackson modules which shall be excluded from json-jackson processing.
+     * the JaxbAnnotationModule is always excluded (cannot be configured).
+     *
+     * @since 2.36
+     */
+
+    public static final String JSON_JACKSON_DISABLED_MODULES = "jersey.config.json.jackson.disabled.modules";
+
+    /**
+     * Client-specific version of {@link CommonProperties#JSON_JACKSON_DISABLED_MODULES}.
+     *
+     * If present, it overrides the generic one for the client environment.
+     * @since 2.36
+     */
+    public static final String JSON_JACKSON_DISABLED_MODULES_CLIENT = "jersey.config.client.json.jackson.disabled.modules";
+
+    /**
+     * Server-specific version of {@link CommonProperties#JSON_JACKSON_DISABLED_MODULES}.
+     *
+     * If present, it overrides the generic one for the client environment.
+     * @since 2.36
+     */
+    public static final String JSON_JACKSON_DISABLED_MODULES_SERVER = "jersey.config.server.json.jackson.disabled.modules";
+
+    /**
      * Prevent instantiation.
      */
     private CommonProperties() {
@@ -274,7 +323,7 @@
      *
      * @since 2.8
      */
-    public static Object getValue(final Map<String, ?> properties, final String propertyName, final Class<?> type) {
+    public static <T> T getValue(final Map<String, ?> properties, final String propertyName, final Class<T> type) {
         return PropertiesHelper.getValue(properties, propertyName, type, CommonProperties.LEGACY_FALLBACK_MAP);
     }
 
diff --git a/core-common/src/main/java/org/glassfish/jersey/logging/ClientLoggingFilter.java b/core-common/src/main/java/org/glassfish/jersey/logging/ClientLoggingFilter.java
index 7a797a0..2b99da6 100644
--- a/core-common/src/main/java/org/glassfish/jersey/logging/ClientLoggingFilter.java
+++ b/core-common/src/main/java/org/glassfish/jersey/logging/ClientLoggingFilter.java
@@ -83,7 +83,7 @@
         printRequestLine(b, "Sending client request", id, context.getMethod(), context.getUri());
         printPrefixedHeaders(b, id, REQUEST_PREFIX, context.getStringHeaders());
 
-        if (context.hasEntity() && printEntity(verbosity, context.getMediaType())) {
+        if (printEntity(verbosity, context.getMediaType()) && context.hasEntity()) {
             final OutputStream stream = new LoggingStream(b, context.getEntityStream());
             context.setEntityStream(stream);
             context.setProperty(ENTITY_LOGGER_PROPERTY, stream);
@@ -107,7 +107,7 @@
         printResponseLine(b, "Client response received", id, responseContext.getStatus());
         printPrefixedHeaders(b, id, RESPONSE_PREFIX, responseContext.getHeaders());
 
-        if (responseContext.hasEntity() && printEntity(verbosity, responseContext.getMediaType())) {
+        if (printEntity(verbosity, responseContext.getMediaType()) && responseContext.hasEntity()) {
             responseContext.setEntityStream(logInboundEntity(b, responseContext.getEntityStream(),
                     MessageUtils.getCharset(responseContext.getMediaType())));
         }
diff --git a/core-common/src/main/java/org/glassfish/jersey/logging/ServerLoggingFilter.java b/core-common/src/main/java/org/glassfish/jersey/logging/ServerLoggingFilter.java
index 7430859..6ed5dfe 100644
--- a/core-common/src/main/java/org/glassfish/jersey/logging/ServerLoggingFilter.java
+++ b/core-common/src/main/java/org/glassfish/jersey/logging/ServerLoggingFilter.java
@@ -83,7 +83,7 @@
         printRequestLine(b, "Server has received a request", id, context.getMethod(), context.getUriInfo().getRequestUri());
         printPrefixedHeaders(b, id, REQUEST_PREFIX, context.getHeaders());
 
-        if (context.hasEntity() && printEntity(verbosity, context.getMediaType())) {
+        if (printEntity(verbosity, context.getMediaType()) && context.hasEntity()) {
             context.setEntityStream(
                     logInboundEntity(b, context.getEntityStream(), MessageUtils.getCharset(context.getMediaType())));
         }
@@ -105,7 +105,7 @@
         printResponseLine(b, "Server responded with a response", id, responseContext.getStatus());
         printPrefixedHeaders(b, id, RESPONSE_PREFIX, responseContext.getStringHeaders());
 
-        if (responseContext.hasEntity() && printEntity(verbosity, responseContext.getMediaType())) {
+        if (printEntity(verbosity, responseContext.getMediaType()) && responseContext.hasEntity()) {
             final OutputStream stream = new LoggingStream(b, responseContext.getEntityStream());
             responseContext.setEntityStream(stream);
             requestContext.setProperty(ENTITY_LOGGER_PROPERTY, stream);
diff --git a/core-common/src/test/java/org/glassfish/jersey/logging/HasEntityTimeoutTest.java b/core-common/src/test/java/org/glassfish/jersey/logging/HasEntityTimeoutTest.java
new file mode 100644
index 0000000..3cd15cb
--- /dev/null
+++ b/core-common/src/test/java/org/glassfish/jersey/logging/HasEntityTimeoutTest.java
@@ -0,0 +1,277 @@
+/*
+ * Copyright (c) 2022 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.logging;
+
+import jakarta.ws.rs.ProcessingException;
+import jakarta.ws.rs.client.ClientRequestContext;
+import jakarta.ws.rs.client.ClientResponseContext;
+import jakarta.ws.rs.container.ContainerRequestContext;
+import jakarta.ws.rs.container.ContainerResponseContext;
+import jakarta.ws.rs.core.MediaType;
+import jakarta.ws.rs.core.MultivaluedHashMap;
+import jakarta.ws.rs.core.UriInfo;
+import org.junit.Test;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+import java.net.SocketTimeoutException;
+import java.net.URI;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+
+public class HasEntityTimeoutTest {
+
+    private enum DirectionType {
+        INBOUND,
+        OUTBOUND
+    }
+
+    private static class UriInfoHandler implements InvocationHandler {
+
+        @Override
+        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
+            switch (method.getName()) {
+                case "getRequestUri":
+                    return URI.create("http://localhost:8080/get");
+            }
+            return null;
+        }
+    }
+
+    private static class RequestResponseHandler implements InvocationHandler {
+        private final DirectionType type;
+
+        private RequestResponseHandler(DirectionType type) {
+            this.type = type;
+        }
+
+        @Override
+        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
+            switch (method.getName()) {
+                case "hasEntity":
+                    throw new ProcessingException(new SocketTimeoutException("Read timed out"));
+                case "getUri":
+                    return URI.create("http://localhost:8080");
+                case "getStringHeaders":
+                case "getHeaders":
+                    return new MultivaluedHashMap<String, String>();
+                case "getMethod":
+                    return "GET";
+                case "getMediaType":
+                    return MediaType.SERVER_SENT_EVENTS_TYPE;
+                case "getEntityStream":
+                    return type == DirectionType.OUTBOUND
+                            ? new ByteArrayOutputStream()
+                            : new ByteArrayInputStream("entity".getBytes());
+                case "getStatus":
+                    return 200;
+                case "getUriInfo":
+                    return Proxy.newProxyInstance(
+                            UriInfo.class.getClassLoader(),
+                            new Class[]{UriInfo.class},
+                            new UriInfoHandler());
+            }
+            return null;
+        }
+    }
+
+    @Test
+    public void testClientFilterTimedOut() throws IOException {
+        ClientLoggingFilter loggingFilter = new ClientLoggingFilter(
+                LoggingFeature.builder()
+                        .withLogger(Logger.getLogger(LoggingFeature.DEFAULT_LOGGER_NAME))
+                        .level(Level.INFO)
+                        .verbosity(LoggingFeature.Verbosity.HEADERS_ONLY)
+                        .maxEntitySize(10)
+        );
+
+        ClientRequestContext clientRequestContext = (ClientRequestContext) Proxy.newProxyInstance(
+                ClientRequestContext.class.getClassLoader(),
+                new Class[]{ClientRequestContext.class},
+                new RequestResponseHandler(DirectionType.OUTBOUND));
+        loggingFilter.filter(clientRequestContext);
+    }
+
+    @Test
+    public void testClientFilterTimedOutException() throws IOException {
+        ClientLoggingFilter loggingFilter = new ClientLoggingFilter(
+                LoggingFeature.builder()
+                        .withLogger(Logger.getLogger(LoggingFeature.DEFAULT_LOGGER_NAME))
+                        .level(Level.INFO)
+                        .verbosity(LoggingFeature.Verbosity.PAYLOAD_ANY)
+                        .maxEntitySize(10)
+        );
+
+        ClientRequestContext clientRequestContext = (ClientRequestContext) Proxy.newProxyInstance(
+                ClientRequestContext.class.getClassLoader(),
+                new Class[]{ClientRequestContext.class},
+                new RequestResponseHandler(DirectionType.OUTBOUND));
+        try {
+            loggingFilter.filter(clientRequestContext);
+            throw new RuntimeException("The expected exception has not been thrown");
+        } catch (ProcessingException pe) {
+            // expected
+        }
+    }
+
+    @Test
+    public void testClientFilterResponseTimedOut() throws IOException {
+        ClientLoggingFilter loggingFilter = new ClientLoggingFilter(
+                LoggingFeature.builder()
+                        .withLogger(Logger.getLogger(LoggingFeature.DEFAULT_LOGGER_NAME))
+                        .level(Level.INFO)
+                        .verbosity(LoggingFeature.Verbosity.HEADERS_ONLY)
+                        .maxEntitySize(10)
+        );
+
+        ClientRequestContext clientRequestContext = (ClientRequestContext) Proxy.newProxyInstance(
+                ClientRequestContext.class.getClassLoader(),
+                new Class[]{ClientRequestContext.class},
+                new RequestResponseHandler(DirectionType.OUTBOUND));
+
+        ClientResponseContext clientResponseContext = (ClientResponseContext) Proxy.newProxyInstance(
+                ClientResponseContext.class.getClassLoader(),
+                new Class[]{ClientResponseContext.class},
+                new RequestResponseHandler(DirectionType.INBOUND));
+        loggingFilter.filter(clientRequestContext, clientResponseContext);
+    }
+
+    @Test
+    public void testClientFilterResponseTimedOutException() throws IOException {
+        ClientLoggingFilter loggingFilter = new ClientLoggingFilter(
+                LoggingFeature.builder()
+                        .withLogger(Logger.getLogger(LoggingFeature.DEFAULT_LOGGER_NAME))
+                        .level(Level.INFO)
+                        .verbosity(LoggingFeature.Verbosity.PAYLOAD_ANY)
+                        .maxEntitySize(10)
+        );
+
+        ClientRequestContext clientRequestContext = (ClientRequestContext) Proxy.newProxyInstance(
+                ClientRequestContext.class.getClassLoader(),
+                new Class[]{ClientRequestContext.class},
+                new RequestResponseHandler(DirectionType.OUTBOUND));
+
+        ClientResponseContext clientResponseContext = (ClientResponseContext) Proxy.newProxyInstance(
+                ClientResponseContext.class.getClassLoader(),
+                new Class[]{ClientResponseContext.class},
+                new RequestResponseHandler(DirectionType.INBOUND));
+
+        try {
+            loggingFilter.filter(clientRequestContext, clientResponseContext);
+            throw new RuntimeException("The expected exception has not been thrown");
+        } catch (ProcessingException pe) {
+            // expected
+        }
+    }
+
+    @Test
+    public void testServerFilterTimedOut() throws IOException {
+        ServerLoggingFilter loggingFilter = new ServerLoggingFilter(
+                LoggingFeature.builder()
+                        .withLogger(Logger.getLogger(LoggingFeature.DEFAULT_LOGGER_NAME))
+                        .level(Level.INFO)
+                        .verbosity(LoggingFeature.Verbosity.HEADERS_ONLY)
+                        .maxEntitySize(10)
+        );
+
+        ContainerRequestContext containerRequestContext = (ContainerRequestContext) Proxy.newProxyInstance(
+                ContainerRequestContext.class.getClassLoader(),
+                new Class[]{ContainerRequestContext.class},
+                new RequestResponseHandler(DirectionType.INBOUND));
+        loggingFilter.filter(containerRequestContext);
+    }
+
+    @Test
+    public void testServerFilterTimedOutException() throws IOException {
+        ServerLoggingFilter loggingFilter = new ServerLoggingFilter(
+                LoggingFeature.builder()
+                        .withLogger(Logger.getLogger(LoggingFeature.DEFAULT_LOGGER_NAME))
+                        .level(Level.INFO)
+                        .verbosity(LoggingFeature.Verbosity.PAYLOAD_ANY)
+                        .maxEntitySize(10)
+        );
+
+        ContainerRequestContext containerRequestContext = (ContainerRequestContext) Proxy.newProxyInstance(
+                ContainerRequestContext.class.getClassLoader(),
+                new Class[]{ContainerRequestContext.class},
+                new RequestResponseHandler(DirectionType.INBOUND));
+
+        try {
+            loggingFilter.filter(containerRequestContext);
+            throw new RuntimeException("The expected exception has not been thrown");
+        } catch (ProcessingException pe) {
+            // expected
+        }
+    }
+
+    @Test
+    public void testServerFilterResponseTimedOut() throws IOException {
+        ServerLoggingFilter loggingFilter = new ServerLoggingFilter(
+                LoggingFeature.builder()
+                        .withLogger(Logger.getLogger(LoggingFeature.DEFAULT_LOGGER_NAME))
+                        .level(Level.INFO)
+                        .verbosity(LoggingFeature.Verbosity.HEADERS_ONLY)
+                        .maxEntitySize(10)
+        );
+
+        ContainerRequestContext containerRequestContext = (ContainerRequestContext) Proxy.newProxyInstance(
+                ContainerRequestContext.class.getClassLoader(),
+                new Class[]{ContainerRequestContext.class},
+                new RequestResponseHandler(DirectionType.INBOUND));
+
+        ContainerResponseContext containerResponseContext = (ContainerResponseContext) Proxy.newProxyInstance(
+                ContainerResponseContext.class.getClassLoader(),
+                new Class[]{ContainerResponseContext.class},
+                new RequestResponseHandler(DirectionType.OUTBOUND));
+
+        loggingFilter.filter(containerRequestContext, containerResponseContext);
+    }
+
+    @Test
+    public void testServerFilterResponseTimedOutException() throws IOException {
+        ServerLoggingFilter loggingFilter = new ServerLoggingFilter(
+                LoggingFeature.builder()
+                        .withLogger(Logger.getLogger(LoggingFeature.DEFAULT_LOGGER_NAME))
+                        .level(Level.INFO)
+                        .verbosity(LoggingFeature.Verbosity.PAYLOAD_ANY)
+                        .maxEntitySize(10)
+        );
+
+        ContainerRequestContext containerRequestContext = (ContainerRequestContext) Proxy.newProxyInstance(
+                ContainerRequestContext.class.getClassLoader(),
+                new Class[]{ContainerRequestContext.class},
+                new RequestResponseHandler(DirectionType.INBOUND));
+
+        ContainerResponseContext containerResponseContext = (ContainerResponseContext) Proxy.newProxyInstance(
+                ContainerResponseContext.class.getClassLoader(),
+                new Class[]{ContainerResponseContext.class},
+                new RequestResponseHandler(DirectionType.OUTBOUND));
+
+        try {
+            loggingFilter.filter(containerRequestContext, containerResponseContext);
+            throw new RuntimeException("The expected exception has not been thrown");
+        } catch (ProcessingException pe) {
+            // expected
+        }
+    }
+
+}
diff --git a/core-server/src/main/java/jersey/repackaged/org/objectweb/asm/AnnotationVisitor.java b/core-server/src/main/java/jersey/repackaged/org/objectweb/asm/AnnotationVisitor.java
index 8ca2039..0654582 100644
--- a/core-server/src/main/java/jersey/repackaged/org/objectweb/asm/AnnotationVisitor.java
+++ b/core-server/src/main/java/jersey/repackaged/org/objectweb/asm/AnnotationVisitor.java
@@ -38,8 +38,8 @@
 public abstract class AnnotationVisitor {
 
   /**
-   * The ASM API version implemented by this visitor. The value of this field must be one of {@link
-   * Opcodes#ASM4}, {@link Opcodes#ASM5}, {@link Opcodes#ASM6} or {@link Opcodes#ASM7}.
+   * The ASM API version implemented by this visitor. The value of this field must be one of the
+   * {@code ASM}<i>x</i> values in {@link Opcodes}.
    */
   protected final int api;
 
@@ -52,22 +52,22 @@
   /**
    * Constructs a new {@link AnnotationVisitor}.
    *
-   * @param api the ASM API version implemented by this visitor. Must be one of {@link
-   *     Opcodes#ASM4}, {@link Opcodes#ASM5}, {@link Opcodes#ASM6} or {@link Opcodes#ASM7}.
+   * @param api the ASM API version implemented by this visitor. Must be one of the {@code
+   *     ASM}<i>x</i> values in {@link Opcodes}.
    */
-  public AnnotationVisitor(final int api) {
+  protected AnnotationVisitor(final int api) {
     this(api, null);
   }
 
   /**
    * Constructs a new {@link AnnotationVisitor}.
    *
-   * @param api the ASM API version implemented by this visitor. Must be one of {@link
-   *     Opcodes#ASM4}, {@link Opcodes#ASM5}, {@link Opcodes#ASM6} or {@link Opcodes#ASM7}.
+   * @param api the ASM API version implemented by this visitor. Must be one of the {@code
+   *     ASM}<i>x</i> values in {@link Opcodes}.
    * @param annotationVisitor the annotation visitor to which this visitor must delegate method
    *     calls. May be {@literal null}.
    */
-  public AnnotationVisitor(final int api, final AnnotationVisitor annotationVisitor) {
+  protected AnnotationVisitor(final int api, final AnnotationVisitor annotationVisitor) {
     if (api != Opcodes.ASM9
         && api != Opcodes.ASM8
         && api != Opcodes.ASM7
diff --git a/core-server/src/main/java/jersey/repackaged/org/objectweb/asm/ByteVector.java b/core-server/src/main/java/jersey/repackaged/org/objectweb/asm/ByteVector.java
index 7b386a0..472318f 100644
--- a/core-server/src/main/java/jersey/repackaged/org/objectweb/asm/ByteVector.java
+++ b/core-server/src/main/java/jersey/repackaged/org/objectweb/asm/ByteVector.java
@@ -66,6 +66,15 @@
   }
 
   /**
+   * Returns the actual number of bytes in this vector.
+   *
+   * @return the actual number of bytes in this vector.
+   */
+  public int size() {
+    return length;
+  }
+
+  /**
    * Puts a byte into this byte vector. The byte vector is automatically enlarged if necessary.
    *
    * @param byteValue a byte.
@@ -352,6 +361,9 @@
    * @param size number of additional bytes that this byte vector should be able to receive.
    */
   private void enlarge(final int size) {
+    if (length > data.length) {
+      throw new AssertionError("Internal error");
+    }
     int doubleCapacity = 2 * data.length;
     int minimalCapacity = length + size;
     byte[] newData = new byte[doubleCapacity > minimalCapacity ? doubleCapacity : minimalCapacity];
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 b0173c8..cd4a6bb 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
@@ -194,7 +194,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.V18) {
+    if (checkClassVersion && readShort(classFileOffset + 6) > Opcodes.V19) {
       throw new IllegalArgumentException(
           "Unsupported class file major version " + readShort(classFileOffset + 6));
     }
@@ -308,12 +308,13 @@
    * @return the content of the given input stream.
    * @throws IOException if a problem occurs during reading.
    */
+  @SuppressWarnings("PMD.UseTryWithResources")
   private static byte[] readStream(final InputStream inputStream, final boolean close)
       throws IOException {
     if (inputStream == null) {
       throw new IOException("Class not found");
     }
-   int bufferSize = calculateBufferSize(inputStream);
+    int bufferSize = computeBufferSize(inputStream);
     try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
       byte[] data = new byte[bufferSize];
       int bytesRead;
@@ -334,19 +335,19 @@
     }
   }
 
-  private static int calculateBufferSize(final InputStream inputStream) throws IOException {
+  private static int computeBufferSize(final InputStream inputStream) throws IOException {
     int expectedLength = inputStream.available();
     /*
-     * Some implementations can return 0 while holding available data
-     * (e.g. new FileInputStream("/proc/a_file"))
-     * Also in some pathological cases a very small number might be returned,
-     * and in this case we use default size
+     * Some implementations can return 0 while holding available data (e.g. new
+     * FileInputStream("/proc/a_file")). Also in some pathological cases a very small number might
+     * be returned, and in this case we use a default size.
      */
     if (expectedLength < 256) {
       return INPUT_STREAM_DATA_CHUNK_SIZE;
     }
     return Math.min(expectedLength, MAX_BUFFER_SIZE);
   }
+
   // -----------------------------------------------------------------------------------------------
   // Accessors
   // -----------------------------------------------------------------------------------------------
diff --git a/core-server/src/main/java/jersey/repackaged/org/objectweb/asm/ClassVisitor.java b/core-server/src/main/java/jersey/repackaged/org/objectweb/asm/ClassVisitor.java
index e3a5b60..8ebf594f 100644
--- a/core-server/src/main/java/jersey/repackaged/org/objectweb/asm/ClassVisitor.java
+++ b/core-server/src/main/java/jersey/repackaged/org/objectweb/asm/ClassVisitor.java
@@ -40,8 +40,8 @@
 public abstract class ClassVisitor {
 
   /**
-   * The ASM API version implemented by this visitor. The value of this field must be one of {@link
-   * Opcodes#ASM4}, {@link Opcodes#ASM5}, {@link Opcodes#ASM6} or {@link Opcodes#ASM7}.
+   * The ASM API version implemented by this visitor. The value of this field must be one of the
+   * {@code ASM}<i>x</i> values in {@link Opcodes}.
    */
   protected final int api;
 
@@ -51,23 +51,22 @@
   /**
    * Constructs a new {@link ClassVisitor}.
    *
-   * @param api the ASM API version implemented by this visitor. Must be one of {@link
-   *     Opcodes#ASM4}, {@link Opcodes#ASM5}, {@link Opcodes#ASM6} or {@link Opcodes#ASM7}.
+   * @param api the ASM API version implemented by this visitor. Must be one of the {@code
+   *     ASM}<i>x</i> values in {@link Opcodes}.
    */
-  public ClassVisitor(final int api) {
+  protected ClassVisitor(final int api) {
     this(api, null);
   }
 
   /**
    * Constructs a new {@link ClassVisitor}.
    *
-   * @param api the ASM API version implemented by this visitor. Must be one of {@link
-   *     Opcodes#ASM4}, {@link Opcodes#ASM5}, {@link Opcodes#ASM6}, {@link Opcodes#ASM7}, {@link
-   *     Opcodes#ASM8} or {@link Opcodes#ASM9}.
+   * @param api the ASM API version implemented by this visitor. Must be one of the {@code
+   *     ASM}<i>x</i> values in {@link Opcodes}.
    * @param classVisitor the class visitor to which this visitor must delegate method calls. May be
    *     null.
    */
-  public ClassVisitor(final int api, final ClassVisitor classVisitor) {
+  protected ClassVisitor(final int api, final ClassVisitor classVisitor) {
    if (api != Opcodes.ASM9
         && api != Opcodes.ASM8
         && api != Opcodes.ASM7
diff --git a/core-server/src/main/java/jersey/repackaged/org/objectweb/asm/ClassWriter.java b/core-server/src/main/java/jersey/repackaged/org/objectweb/asm/ClassWriter.java
index 81176b8..de2c441 100644
--- a/core-server/src/main/java/jersey/repackaged/org/objectweb/asm/ClassWriter.java
+++ b/core-server/src/main/java/jersey/repackaged/org/objectweb/asm/ClassWriter.java
@@ -65,6 +65,12 @@
    */
   public static final int COMPUTE_FRAMES = 2;
 
+  /**
+   * The flags passed to the constructor. Must be zero or more of {@link #COMPUTE_MAXS} and {@link
+   * #COMPUTE_FRAMES}.
+   */
+  private final int flags;
+
   // Note: fields are ordered as in the ClassFile structure, and those related to attributes are
   // ordered as in Section 4.7 of the JVMS.
 
@@ -248,24 +254,40 @@
    * @param classReader the {@link ClassReader} used to read the original class. It will be used to
    *     copy the entire constant pool and bootstrap methods from the original class and also to
    *     copy other fragments of original bytecode where applicable.
-   * @param flags option flags that can be used to modify the default behavior of this class.Must be
-   *     zero or more of {@link #COMPUTE_MAXS} and {@link #COMPUTE_FRAMES}. <i>These option flags do
-   *     not affect methods that are copied as is in the new class. This means that neither the
+   * @param flags option flags that can be used to modify the default behavior of this class. Must
+   *     be zero or more of {@link #COMPUTE_MAXS} and {@link #COMPUTE_FRAMES}. <i>These option flags
+   *     do not affect methods that are copied as is in the new class. This means that neither the
    *     maximum stack size nor the stack frames will be computed for these methods</i>.
    */
   public ClassWriter(final ClassReader classReader, final int flags) {
     super(/* latest api = */ Opcodes.ASM9);
+    this.flags = flags;
     symbolTable = classReader == null ? new SymbolTable(this) : new SymbolTable(this, classReader);
     if ((flags & COMPUTE_FRAMES) != 0) {
-      this.compute = MethodWriter.COMPUTE_ALL_FRAMES;
+      compute = MethodWriter.COMPUTE_ALL_FRAMES;
     } else if ((flags & COMPUTE_MAXS) != 0) {
-      this.compute = MethodWriter.COMPUTE_MAX_STACK_AND_LOCAL;
+      compute = MethodWriter.COMPUTE_MAX_STACK_AND_LOCAL;
     } else {
-      this.compute = MethodWriter.COMPUTE_NOTHING;
+      compute = MethodWriter.COMPUTE_NOTHING;
     }
   }
 
   // -----------------------------------------------------------------------------------------------
+  // Accessors
+  // -----------------------------------------------------------------------------------------------
+
+  /**
+   * Returns true if all the given flags were passed to the constructor.
+   *
+   * @param flags some option flags. Must be zero or more of {@link #COMPUTE_MAXS} and {@link
+   *     #COMPUTE_FRAMES}.
+   * @return true if all the given flags, or more, were passed to the constructor.
+   */
+  public boolean hasFlags(final int flags) {
+    return (this.flags & flags) == flags;
+  }
+
+  // -----------------------------------------------------------------------------------------------
   // Implementation of the ClassVisitor abstract class
   // -----------------------------------------------------------------------------------------------
 
diff --git a/core-server/src/main/java/jersey/repackaged/org/objectweb/asm/FieldVisitor.java b/core-server/src/main/java/jersey/repackaged/org/objectweb/asm/FieldVisitor.java
index 716d6b0..64865d6 100644
--- a/core-server/src/main/java/jersey/repackaged/org/objectweb/asm/FieldVisitor.java
+++ b/core-server/src/main/java/jersey/repackaged/org/objectweb/asm/FieldVisitor.java
@@ -37,9 +37,8 @@
 public abstract class FieldVisitor {
 
   /**
-   * The ASM API version implemented by this visitor. The value of this field must be one of {@link
-   * Opcodes#ASM4}, {@link Opcodes#ASM5}, {@link Opcodes#ASM6}, {@link Opcodes#ASM7}, {@link
-   * Opcodes#ASM8} or {@link Opcodes#ASM9}.
+   * The ASM API version implemented by this visitor. The value of this field must be one of the
+   * {@code ASM}<i>x</i> values in {@link Opcodes}.
    */
   protected final int api;
 
@@ -49,24 +48,22 @@
   /**
    * Constructs a new {@link FieldVisitor}.
    *
-   * @param api the ASM API version implemented by this visitor. Must be one of {@link
-   *     Opcodes#ASM4}, {@link Opcodes#ASM5}, {@link Opcodes#ASM6}, {@link Opcodes#ASM7}, {@link
-   *     Opcodes#ASM8} or {@link Opcodes#ASM9}.
+   * @param api the ASM API version implemented by this visitor. Must be one of the {@code
+   *     ASM}<i>x</i> values in {@link Opcodes}.
    */
-  public FieldVisitor(final int api) {
+  protected FieldVisitor(final int api) {
     this(api, null);
   }
 
   /**
    * Constructs a new {@link FieldVisitor}.
    *
-   * @param api the ASM API version implemented by this visitor. Must be one of {@link
-   *     Opcodes#ASM4}, {@link Opcodes#ASM5}, {@link Opcodes#ASM6}, {@link Opcodes#ASM7} or {@link
-   *     Opcodes#ASM8}.
+   * @param api the ASM API version implemented by this visitor. Must be one of the {@code
+   *     ASM}<i>x</i> values in {@link Opcodes}.
    * @param fieldVisitor the field visitor to which this visitor must delegate method calls. May be
    *     null.
    */
-  public FieldVisitor(final int api, final FieldVisitor fieldVisitor) {
+  protected FieldVisitor(final int api, final FieldVisitor fieldVisitor) {
     if (api != Opcodes.ASM9
         && api != Opcodes.ASM8
         && api != Opcodes.ASM7
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 77392c7..805aed5 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
@@ -51,8 +51,8 @@
   private static final String REQUIRES_ASM5 = "This feature requires ASM5";
 
   /**
-   * The ASM API version implemented by this visitor. The value of this field must be one of {@link
-   * Opcodes#ASM4}, {@link Opcodes#ASM5}, {@link Opcodes#ASM6} or {@link Opcodes#ASM7}.
+   * The ASM API version implemented by this visitor. The value of this field must be one of the
+   * {@code ASM}<i>x</i> values in {@link Opcodes}.
    */
   protected final int api;
 
@@ -64,22 +64,22 @@
   /**
    * Constructs a new {@link MethodVisitor}.
    *
-   * @param api the ASM API version implemented by this visitor. Must be one of {@link
-   *     Opcodes#ASM4}, {@link Opcodes#ASM5}, {@link Opcodes#ASM6} or {@link Opcodes#ASM7}.
+   * @param api the ASM API version implemented by this visitor. Must be one of the {@code
+   *     ASM}<i>x</i> values in {@link Opcodes}.
    */
-  public MethodVisitor(final int api) {
+  protected MethodVisitor(final int api) {
     this(api, null);
   }
 
   /**
    * Constructs a new {@link MethodVisitor}.
    *
-   * @param api the ASM API version implemented by this visitor. Must be one of {@link
-   *     Opcodes#ASM4}, {@link Opcodes#ASM5}, {@link Opcodes#ASM6} or {@link Opcodes#ASM7}.
+   * @param api the ASM API version implemented by this visitor. Must be one of the {@code
+   *     ASM}<i>x</i> values in {@link Opcodes}.
    * @param methodVisitor the method visitor to which this visitor must delegate method calls. May
    *     be null.
    */
-  public MethodVisitor(final int api, final MethodVisitor methodVisitor) {
+  protected MethodVisitor(final int api, final MethodVisitor methodVisitor) {
     if (api != Opcodes.ASM9
         && api != Opcodes.ASM8
         && api != Opcodes.ASM7
@@ -351,12 +351,12 @@
    *
    * @param opcode the opcode of the local variable instruction to be visited. This opcode is either
    *     ILOAD, LLOAD, FLOAD, DLOAD, ALOAD, ISTORE, LSTORE, FSTORE, DSTORE, ASTORE or RET.
-   * @param var the operand of the instruction to be visited. This operand is the index of a local
-   *     variable.
+   * @param varIndex the operand of the instruction to be visited. This operand is the index of a
+   *     local variable.
    */
-  public void visitVarInsn(final int opcode, final int var) {
+  public void visitVarInsn(final int opcode, final int varIndex) {
     if (mv != null) {
-      mv.visitVarInsn(opcode, var);
+      mv.visitVarInsn(opcode, varIndex);
     }
   }
 
@@ -554,12 +554,12 @@
   /**
    * Visits an IINC instruction.
    *
-   * @param var index of the local variable to be incremented.
+   * @param varIndex index of the local variable to be incremented.
    * @param increment amount to increment the local variable by.
    */
-  public void visitIincInsn(final int var, final int increment) {
+  public void visitIincInsn(final int varIndex, final int increment) {
     if (mv != null) {
-      mv.visitIincInsn(var, increment);
+      mv.visitIincInsn(varIndex, increment);
     }
   }
 
diff --git a/core-server/src/main/java/jersey/repackaged/org/objectweb/asm/MethodWriter.java b/core-server/src/main/java/jersey/repackaged/org/objectweb/asm/MethodWriter.java
index 24f7f61..ea2e4e4 100644
--- a/core-server/src/main/java/jersey/repackaged/org/objectweb/asm/MethodWriter.java
+++ b/core-server/src/main/java/jersey/repackaged/org/objectweb/asm/MethodWriter.java
@@ -466,7 +466,8 @@
 
   /**
    * Indicates what must be computed. Must be one of {@link #COMPUTE_ALL_FRAMES}, {@link
-   * #COMPUTE_INSERTED_FRAMES}, {@link #COMPUTE_MAX_STACK_AND_LOCAL} or {@link #COMPUTE_NOTHING}.
+   * #COMPUTE_INSERTED_FRAMES}, {@link COMPUTE_MAX_STACK_AND_LOCAL_FROM_FRAMES}, {@link
+   * #COMPUTE_MAX_STACK_AND_LOCAL} or {@link #COMPUTE_NOTHING}.
    */
   private final int compute;
 
@@ -904,26 +905,26 @@
   }
 
   @Override
-  public void visitVarInsn(final int opcode, final int var) {
+  public void visitVarInsn(final int opcode, final int varIndex) {
     lastBytecodeOffset = code.length;
     // Add the instruction to the bytecode of the method.
-    if (var < 4 && opcode != Opcodes.RET) {
+    if (varIndex < 4 && opcode != Opcodes.RET) {
       int optimizedOpcode;
       if (opcode < Opcodes.ISTORE) {
-        optimizedOpcode = Constants.ILOAD_0 + ((opcode - Opcodes.ILOAD) << 2) + var;
+        optimizedOpcode = Constants.ILOAD_0 + ((opcode - Opcodes.ILOAD) << 2) + varIndex;
       } else {
-        optimizedOpcode = Constants.ISTORE_0 + ((opcode - Opcodes.ISTORE) << 2) + var;
+        optimizedOpcode = Constants.ISTORE_0 + ((opcode - Opcodes.ISTORE) << 2) + varIndex;
       }
       code.putByte(optimizedOpcode);
-    } else if (var >= 256) {
-      code.putByte(Constants.WIDE).put12(opcode, var);
+    } else if (varIndex >= 256) {
+      code.putByte(Constants.WIDE).put12(opcode, varIndex);
     } else {
-      code.put11(opcode, var);
+      code.put11(opcode, varIndex);
     }
     // If needed, update the maximum stack size and number of locals, and stack map frames.
     if (currentBasicBlock != null) {
       if (compute == COMPUTE_ALL_FRAMES || compute == COMPUTE_INSERTED_FRAMES) {
-        currentBasicBlock.frame.execute(opcode, var, null, null);
+        currentBasicBlock.frame.execute(opcode, varIndex, null, null);
       } else {
         if (opcode == Opcodes.RET) {
           // No stack size delta.
@@ -945,9 +946,9 @@
           || opcode == Opcodes.DLOAD
           || opcode == Opcodes.LSTORE
           || opcode == Opcodes.DSTORE) {
-        currentMaxLocals = var + 2;
+        currentMaxLocals = varIndex + 2;
       } else {
-        currentMaxLocals = var + 1;
+        currentMaxLocals = varIndex + 1;
       }
       if (currentMaxLocals > maxLocals) {
         maxLocals = currentMaxLocals;
@@ -1307,21 +1308,21 @@
   }
 
   @Override
-  public void visitIincInsn(final int var, final int increment) {
+  public void visitIincInsn(final int varIndex, final int increment) {
     lastBytecodeOffset = code.length;
     // Add the instruction to the bytecode of the method.
-    if ((var > 255) || (increment > 127) || (increment < -128)) {
-      code.putByte(Constants.WIDE).put12(Opcodes.IINC, var).putShort(increment);
+    if ((varIndex > 255) || (increment > 127) || (increment < -128)) {
+      code.putByte(Constants.WIDE).put12(Opcodes.IINC, varIndex).putShort(increment);
     } else {
-      code.putByte(Opcodes.IINC).put11(var, increment);
+      code.putByte(Opcodes.IINC).put11(varIndex, increment);
     }
     // If needed, update the maximum stack size and number of locals, and stack map frames.
     if (currentBasicBlock != null
         && (compute == COMPUTE_ALL_FRAMES || compute == COMPUTE_INSERTED_FRAMES)) {
-      currentBasicBlock.frame.execute(Opcodes.IINC, var, null, null);
+      currentBasicBlock.frame.execute(Opcodes.IINC, varIndex, null, null);
     }
     if (compute != COMPUTE_NOTHING) {
-      int currentMaxLocals = var + 1;
+      int currentMaxLocals = varIndex + 1;
       if (currentMaxLocals > maxLocals) {
         maxLocals = currentMaxLocals;
       }
diff --git a/core-server/src/main/java/jersey/repackaged/org/objectweb/asm/ModuleVisitor.java b/core-server/src/main/java/jersey/repackaged/org/objectweb/asm/ModuleVisitor.java
index 0089d06..9667590 100644
--- a/core-server/src/main/java/jersey/repackaged/org/objectweb/asm/ModuleVisitor.java
+++ b/core-server/src/main/java/jersey/repackaged/org/objectweb/asm/ModuleVisitor.java
@@ -53,7 +53,7 @@
    * @param api the ASM API version implemented by this visitor. Must be one of {@link Opcodes#ASM6}
    *     or {@link Opcodes#ASM7}.
    */
-  public ModuleVisitor(final int api) {
+  protected ModuleVisitor(final int api) {
     this(api, null);
   }
 
@@ -65,7 +65,7 @@
    * @param moduleVisitor the module visitor to which this visitor must delegate method calls. May
    *     be null.
    */
-  public ModuleVisitor(final int api, final ModuleVisitor moduleVisitor) {
+  protected ModuleVisitor(final int api, final ModuleVisitor moduleVisitor) {
     if (api != Opcodes.ASM9
         && api != Opcodes.ASM8
         && api != Opcodes.ASM7
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 7850f21..0a591ec 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
@@ -284,6 +284,7 @@
   int V16 = 0 << 16 | 60;
   int V17 = 0 << 16 | 61;
   int V18 = 0 << 16 | 62;
+  int V19 = 0 << 16 | 63;
 
   /**
    * Version flag indicating that the class is using 'preview' features.
diff --git a/core-server/src/main/java/jersey/repackaged/org/objectweb/asm/RecordComponentVisitor.java b/core-server/src/main/java/jersey/repackaged/org/objectweb/asm/RecordComponentVisitor.java
index bab13ad..65cf92c 100644
--- a/core-server/src/main/java/jersey/repackaged/org/objectweb/asm/RecordComponentVisitor.java
+++ b/core-server/src/main/java/jersey/repackaged/org/objectweb/asm/RecordComponentVisitor.java
@@ -53,7 +53,7 @@
    * @param api the ASM API version implemented by this visitor. Must be one of {@link Opcodes#ASM8}
    *     or {@link Opcodes#ASM9}.
    */
-  public RecordComponentVisitor(final int api) {
+  protected RecordComponentVisitor(final int api) {
     this(api, null);
   }
 
@@ -64,7 +64,7 @@
    * @param recordComponentVisitor the record component visitor to which this visitor must delegate
    *     method calls. May be null.
    */
-  public RecordComponentVisitor(
+  protected RecordComponentVisitor(
       final int api, final RecordComponentVisitor recordComponentVisitor) {
     if (api != Opcodes.ASM9
         && api != Opcodes.ASM8
diff --git a/core-server/src/main/java/jersey/repackaged/org/objectweb/asm/Type.java b/core-server/src/main/java/jersey/repackaged/org/objectweb/asm/Type.java
index dbe11cc..ab8687e 100644
--- a/core-server/src/main/java/jersey/repackaged/org/objectweb/asm/Type.java
+++ b/core-server/src/main/java/jersey/repackaged/org/objectweb/asm/Type.java
@@ -440,7 +440,7 @@
       case '(':
         return new Type(METHOD, descriptorBuffer, descriptorBegin, descriptorEnd);
       default:
-        throw new IllegalArgumentException();
+        throw new IllegalArgumentException("Invalid descriptor: " + descriptorBuffer);
     }
   }
 
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 cdb34b1..60fdf20 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, 2021 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2022 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
@@ -303,7 +303,7 @@
 
     private static class ClassReaderWrapper {
         private static final Logger LOGGER = Logger.getLogger(ClassReader.class.getName());
-        private static final int WARN_VERSION = Opcodes.V18;
+        private static final int WARN_VERSION = Opcodes.V19;
         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 c95dd3a..9399ca7 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.0

+org.objectweb.asm Version 9.3

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

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

 

diff --git a/docs/src/main/docbook/appendix-properties.xml b/docs/src/main/docbook/appendix-properties.xml
index a3232c6..9a0c4d6 100644
--- a/docs/src/main/docbook/appendix-properties.xml
+++ b/docs/src/main/docbook/appendix-properties.xml
@@ -148,6 +148,42 @@
                         </entry>
                     </row>
                     <row>
+                        <entry>&jersey.common.CommonProperties.JSON_JACKSON_ENABLED_MODULES; /
+                        <entry>&jersey.common.CommonProperties.JSON_JACKSON_ENABLED_MODULES_CLIENT; /
+                        <entry>&jersey.common.CommonProperties.JSON_JACKSON_ENABLED_MODULES_SERVER;
+                        </entry>
+                        <entry>
+                            <literal>jersey.config.json.jackson.enabled.modules</literal>
+                            <literal>jersey.config.client.json.jackson.enabled.modules</literal>
+                            <literal>jersey.config.server.json.jackson.enabled.modules</literal>
+                        </entry>
+                        <entry>
+                            Comma separated list of jackson modules which shall be used for json-jackson provider.
+                            If set, only those modules will be used for JSON processing.
+
+                            Default value is <literal>NULL</literal>
+                            @since 2.36
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>&jersey.common.CommonProperties.JSON_JACKSON_DISABLED_MODULES; /
+                        <entry>&jersey.common.CommonProperties.JSON_JACKSON_DISABLED_MODULES_CLIENT; /
+                        <entry>&jersey.common.CommonProperties.JSON_JACKSON_DISABLED_MODULES_SERVER;
+                        </entry>
+                        <entry>
+                            <literal>jersey.config.json.jackson.disabled.modules</literal>
+                            <literal>jersey.config.client.json.jackson.disabled.modules</literal>
+                            <literal>jersey.config.server.json.jackson.disabled.modules</literal>
+                        </entry>
+                        <entry>
+                            Comma separated list of jackson modules which shall be excluded from json-jackson provider.
+                            If set, those modules will be excluded from JSON processing.
+
+                            Default value is <literal>NULL</literal>
+                            @since 2.36
+                        </entry>
+                    </row>
+                    <row>
                         <entry>&jersey.logging.LoggingFeature.LOGGING_FEATURE_LOGGER_NAME;
                         </entry>
                         <entry>
@@ -1845,6 +1881,18 @@
                             </para>
                         </entry>
                     </row>
+                    <row>
+                        <entry>&jersey.netty.NettyClientProperties.MAX_REDIRECTS;</entry>
+                        <entry><literal>jersey.config.client.NettyConnectorProvider.maxRedirect</literal></entry>
+                        <entry>
+                            <para>
+                                This property determines the maximal number of redirects during single request. Value is expected to be
+                                positive number. Default value is 5.
+                                HTTP redirection must be enabled by property org.glassfish.jersey.client.ClientProperties.FOLLOW_REDIRECTS
+                                otherwise &jersey.netty.NettyClientProperties.MAX_REDIRECTS; is not applied.
+                            </para>
+                        </entry>
+                    </row>
                 </tbody>
             </tgroup>
         </table>
diff --git a/docs/src/main/docbook/jersey.ent b/docs/src/main/docbook/jersey.ent
index 800c3f9..2f91101 100644
--- a/docs/src/main/docbook/jersey.ent
+++ b/docs/src/main/docbook/jersey.ent
@@ -396,6 +396,12 @@
 <!ENTITY jersey.common.CommonProperties.OUTBOUND_CONTENT_LENGTH_BUFFER_CLIENT "<link xlink:href='&jersey.javadoc.uri.prefix;/CommonProperties.html#OUTBOUND_CONTENT_LENGTH_BUFFER_CLIENT'>CommonProperties.OUTBOUND_CONTENT_LENGTH_BUFFER_CLIENT</link>" >
 <!ENTITY jersey.common.CommonProperties.OUTBOUND_CONTENT_LENGTH_BUFFER_SERVER "<link xlink:href='&jersey.javadoc.uri.prefix;/CommonProperties.html#OUTBOUND_CONTENT_LENGTH_BUFFER_SERVER'>CommonProperties.OUTBOUND_CONTENT_LENGTH_BUFFER_SERVER</link>" >
 <!ENTITY jersey.common.CommonProperties.PROVIDER_DEFAULT_DISABLE "<link xlink:href='&jersey.javadoc.uri.prefix;/CommonProperties.html#PROVIDER_DEFAULT_DISABLE'>CommonProperties.PROVIDER_DEFAULT_DISABLE</link>" >
+<!ENTITY jersey.common.CommonProperties.JSON_JACKSON_ENABLED_MODULES "<link xlink:href='&jersey.javadoc.uri.prefix;/CommonProperties.html#JSON_JACKSON_ENABLED_MODULES'>CommonProperties.JSON_JACKSON_ENABLED_MODULES</link>" >
+<!ENTITY jersey.common.CommonProperties.JSON_JACKSON_ENABLED_MODULES_CLIENT "<link xlink:href='&jersey.javadoc.uri.prefix;/CommonProperties.html#JSON_JACKSON_ENABLED_MODULES'>CommonProperties.JSON_JACKSON_ENABLED_MODULES_CLIENT</link>" >
+<!ENTITY jersey.common.CommonProperties.JSON_JACKSON_ENABLED_MODULES_SERVER "<link xlink:href='&jersey.javadoc.uri.prefix;/CommonProperties.html#JSON_JACKSON_ENABLED_MODULES'>CommonProperties.JSON_JACKSON_ENABLED_MODULES_SERVER</link>" >
+<!ENTITY jersey.common.CommonProperties.JSON_JACKSON_DISABLED_MODULES "<link xlink:href='&jersey.javadoc.uri.prefix;/CommonProperties.html#JSON_JACKSON_DISABLED_MODULES'>CommonProperties.JSON_JACKSON_DISABLED_MODULES</link>" >
+<!ENTITY jersey.common.CommonProperties.JSON_JACKSON_DISABLED_MODULES_CLIENT "<link xlink:href='&jersey.javadoc.uri.prefix;/CommonProperties.html#JSON_JACKSON_DISABLED_MODULES'>CommonProperties.JSON_JACKSON_DISABLED_MODULES_CLIENT</link>" >
+<!ENTITY jersey.common.CommonProperties.JSON_JACKSON_DISABLED_MODULES_SERVER "<link xlink:href='&jersey.javadoc.uri.prefix;/CommonProperties.html#JSON_JACKSON_DISABLED_MODULES'>CommonProperties.JSON_JACKSON_DISABLED_MODULES_SERVER</link>" >
 <!ENTITY jersey.common.internal.inject.DisposableSupplier "<link xlink:href='&jersey.javadoc.uri.prefix;/internal/inject/DisposableSupplier.html'>DisposableSupplier</link>">
 <!ENTITY jersey.common.internal.inject.InjectionManager "<link xlink:href='&jersey.javadoc.uri.prefix;/internal/inject/InjectionManager.html'>InjectionManager</link>">
 <!ENTITY jersey.common.internal.inject.AbstractBinder "<link xlink:href='&jersey.javadoc.uri.prefix;/internal/inject/AbstractBinder.html'>AbstractBinder</link>">
@@ -537,6 +543,7 @@
 <!ENTITY jersey.netty.NettyClientProperties.IDLE_CONNECTION_PRUNE_TIMEOUT "<link xlink:href='&jersey.javadoc.uri.prefix;/netty/connector/NettyClientProperties.html#IDLE_CONNECTION_PRUNE_TIMEOUT'>NettyClientProperties.IDLE_CONNECTION_PRUNE_TIMEOUT</link>" >
 <!ENTITY jersey.netty.NettyClientProperties.MAX_CONNECTIONS "<link xlink:href='&jersey.javadoc.uri.prefix;/netty/connector/NettyClientProperties.html#MAX_CONNECTIONS'>NettyClientProperties.MAX_CONNECTIONS</link>" >
 <!ENTITY jersey.netty.NettyClientProperties.MAX_CONNECTIONS_TOTAL "<link xlink:href='&jersey.javadoc.uri.prefix;/netty/connector/NettyClientProperties.html#MAX_CONNECTIONS_TOTAL'>NettyClientProperties.MAX_CONNECTIONS_TOTAL</link>" >
+<!ENTITY jersey.netty.NettyClientProperties.MAX_REDIRECTS "<link xlink:href='&jersey.javadoc.uri.prefix;/netty/connector/NettyClientProperties.html#MAX_REDIRECTS'>NettyClientProperties.MAX_REDIRECTS</link>" >
 <!ENTITY jersey.netty.NettyConnectorProvider "<link xlink:href='&jersey.javadoc.uri.prefix;/netty/connector/NettyConnectorProvider.html'>NettyConnectorProvider</link>">
 <!ENTITY jersey.server.ApplicationHandler "<link xlink:href='&jersey.javadoc.uri.prefix;/server/ApplicationHandler.html'>ApplicationHandler</link>">
 <!ENTITY jersey.server.BackgroundScheduler "<link xlink:href='&jersey.javadoc.uri.prefix;/server/BackgroundScheduler.html'>@BackgroundScheduler</link>">
diff --git a/docs/src/main/docbook/media.xml b/docs/src/main/docbook/media.xml
index 95581df..f830e90 100644
--- a/docs/src/main/docbook/media.xml
+++ b/docs/src/main/docbook/media.xml
@@ -1,7 +1,7 @@
 <?xml version="1.0" standalone="no"?>
 <!--
 
-    Copyright (c) 2012, 2021 Oracle and/or its affiliates. All rights reserved.
+    Copyright (c) 2012, 2022 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
@@ -570,6 +570,15 @@
                 </para>
 
                 <para>
+                    Since the 2.36 version of Jersey it is possible to filter (include/exclude) Jackson modules by properties
+                    &jersey.common.CommonProperties.JSON_JACKSON_DISABLED_MODULES; and &jersey.common.CommonProperties.JSON_JACKSON_ENABLED_MODULES;
+                    (with their client/server derivatives). If the &jersey.common.CommonProperties.JSON_JACKSON_ENABLED_MODULES; property is used,
+                    only those named modules will be used for JSON processing. On the other hand if the &jersey.common.CommonProperties.JSON_JACKSON_DISABLED_MODULES;
+                    property is used, those listed modules will be explicitly excluded from processing while other (not listed) will remain. Please note that
+                    the <literal>JaxbAnnotationModule</literal> module is always excluded from processing and this is not configurable.
+                </para>
+
+                <para>
                     In order to use Jackson as your JSON (JAXB/POJO) provider you need to register &jersey.media.JacksonFeature;
                     and a &lit.jaxrs.ext.ContextResolver; for &lit.jersey.media.ObjectMapper;,
                     if needed, in your &jaxrs.core.Configurable; (client/server).
diff --git a/media/json-jackson/src/main/java/org/glassfish/jersey/jackson/internal/DefaultJacksonJaxbJsonProvider.java b/media/json-jackson/src/main/java/org/glassfish/jersey/jackson/internal/DefaultJacksonJaxbJsonProvider.java
index f4f0f3f..527f1db 100644
--- a/media/json-jackson/src/main/java/org/glassfish/jersey/jackson/internal/DefaultJacksonJaxbJsonProvider.java
+++ b/media/json-jackson/src/main/java/org/glassfish/jersey/jackson/internal/DefaultJacksonJaxbJsonProvider.java
@@ -18,11 +18,16 @@
 
 import com.fasterxml.jackson.databind.ObjectMapper;
 import com.fasterxml.jackson.databind.Module;
+import org.glassfish.jersey.CommonProperties;
 import org.glassfish.jersey.jackson.internal.jackson.jaxrs.cfg.Annotations;
 import org.glassfish.jersey.jackson.internal.jackson.jaxrs.json.JacksonJaxbJsonProvider;
 
+import java.util.Arrays;
 import java.util.List;
+import jakarta.annotation.PostConstruct;
 import jakarta.inject.Singleton;
+import jakarta.ws.rs.core.Configuration;
+import jakarta.ws.rs.core.Context;
 
 /**
  * Entity Data provider based on Jackson JSON provider.
@@ -30,32 +35,57 @@
 @Singleton
 public class DefaultJacksonJaxbJsonProvider extends JacksonJaxbJsonProvider {
 
+    @Context
+    private Configuration commonConfig;
+
     //do not register JaxbAnnotationModule because it brakes default annotations processing
     private static final String[] EXCLUDE_MODULE_NAMES = {"JaxbAnnotationModule", "JakartaXmlBindAnnotationModule"};
 
     public DefaultJacksonJaxbJsonProvider() {
         super(new JacksonMapperConfigurator(null, DEFAULT_ANNOTATIONS));
-        findAndRegisterModules();
     }
 
     public DefaultJacksonJaxbJsonProvider(final Annotations... annotationsToUse) {
         super(new JacksonMapperConfigurator(null, annotationsToUse));
-        findAndRegisterModules();
     }
 
+    @PostConstruct
     private void findAndRegisterModules() {
 
         final ObjectMapper defaultMapper = _mapperConfig.getDefaultMapper();
         final ObjectMapper mapper = _mapperConfig.getConfiguredMapper();
 
+        final List<Module> modules =  filterModules();
+
+        defaultMapper.registerModules(modules);
+        if (mapper != null) {
+            mapper.registerModules(modules);
+        }
+    }
+
+    private List<Module> filterModules() {
+        final String disabledModules =
+                CommonProperties.getValue(commonConfig.getProperties(),
+                        commonConfig.getRuntimeType(),
+                        CommonProperties.JSON_JACKSON_DISABLED_MODULES, String.class);
+        final String enabledModules =
+                CommonProperties.getValue(commonConfig.getProperties(),
+                        commonConfig.getRuntimeType(),
+                        CommonProperties.JSON_JACKSON_ENABLED_MODULES, String.class);
+
         final List<Module> modules = ObjectMapper.findModules();
         for (String exludeModuleName : EXCLUDE_MODULE_NAMES) {
             modules.removeIf(mod -> mod.getModuleName().contains(exludeModuleName));
         }
 
-        defaultMapper.registerModules(modules);
-        if (mapper != null) {
-            mapper.registerModules(modules);
+        if (enabledModules != null && !enabledModules.isEmpty()) {
+            final List<String> enabledModulesList = Arrays.asList(enabledModules.split(","));
+            modules.removeIf(mod -> !enabledModulesList.contains(mod.getModuleName()));
+        } else if (disabledModules != null && !disabledModules.isEmpty()) {
+            final List<String> disabledModulesList = Arrays.asList(disabledModules.split(","));
+            modules.removeIf(mod -> disabledModulesList.contains(mod.getModuleName()));
         }
+
+        return modules;
     }
 }
\ No newline at end of file
diff --git a/media/json-jackson/src/main/java/org/glassfish/jersey/jackson/internal/jackson/jaxrs/base/ProviderBase.java b/media/json-jackson/src/main/java/org/glassfish/jersey/jackson/internal/jackson/jaxrs/base/ProviderBase.java
index 1127535..b793cb1 100644
--- a/media/json-jackson/src/main/java/org/glassfish/jersey/jackson/internal/jackson/jaxrs/base/ProviderBase.java
+++ b/media/json-jackson/src/main/java/org/glassfish/jersey/jackson/internal/jackson/jaxrs/base/ProviderBase.java
@@ -12,7 +12,6 @@
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
-import java.util.concurrent.atomic.AtomicReference;
 
 import jakarta.ws.rs.core.MediaType;
 import jakarta.ws.rs.core.MultivaluedMap;
@@ -63,7 +62,7 @@
      */
     public final static String HEADER_CONTENT_TYPE_OPTIONS = "X-Content-Type-Options";
 
-    protected final static String CLASS_NAME_NO_CONTENT_EXCEPTION = "javax.ws.rs.core.NoContentException";
+    protected final static String CLASS_NAME_NO_CONTENT_EXCEPTION = "jakarta.ws.rs.core.NoContentException";
 
     private final static String NO_CONTENT_MESSAGE = "No content (empty input stream)";
 
diff --git a/media/json-jackson/src/main/java/org/glassfish/jersey/jackson/internal/jackson/jaxrs/json/PackageVersion.java b/media/json-jackson/src/main/java/org/glassfish/jersey/jackson/internal/jackson/jaxrs/json/PackageVersion.java
index 9974df6..0389a9c 100644
--- a/media/json-jackson/src/main/java/org/glassfish/jersey/jackson/internal/jackson/jaxrs/json/PackageVersion.java
+++ b/media/json-jackson/src/main/java/org/glassfish/jersey/jackson/internal/jackson/jaxrs/json/PackageVersion.java
@@ -11,7 +11,7 @@
  */
 public final class PackageVersion implements Versioned {
     public final static Version VERSION = VersionUtil.parseVersion(
-        "2.13.0", "com.fasterxml.jackson.jaxrs", "jackson-jaxrs-json-provider");
+        "2.13.3", "com.fasterxml.jackson.jaxrs", "jackson-jaxrs-json-provider");
 
     @Override
     public Version version() {
diff --git a/media/json-jackson/src/main/resources/META-INF/NOTICE.markdown b/media/json-jackson/src/main/resources/META-INF/NOTICE.markdown
index c383a09..f35a86b 100644
--- a/media/json-jackson/src/main/resources/META-INF/NOTICE.markdown
+++ b/media/json-jackson/src/main/resources/META-INF/NOTICE.markdown
@@ -31,7 +31,7 @@
 

 ## Third-party Content

 

-Jackson JAX-RS Providers version 2.11.3

+Jackson JAX-RS Providers version 2.13.3

 * License: Apache License, 2.0

 * Project: https://github.com/FasterXML/jackson-jaxrs-providers

-* Copyright: (c) 2009-2011 FasterXML, LLC. All rights reserved unless otherwise indicated.
\ No newline at end of file
+* Copyright: (c) 2009-2022 FasterXML, LLC. All rights reserved unless otherwise indicated.

diff --git a/media/json-jackson/src/test/java/org/glassfish/jersey/jackson/internal/DefaultJsonJacksonProviderForBothModulesTest.java b/media/json-jackson/src/test/java/org/glassfish/jersey/jackson/internal/DefaultJsonJacksonProviderForBothModulesTest.java
new file mode 100644
index 0000000..947d599
--- /dev/null
+++ b/media/json-jackson/src/test/java/org/glassfish/jersey/jackson/internal/DefaultJsonJacksonProviderForBothModulesTest.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2022 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.jackson.internal;
+
+import org.glassfish.jersey.jackson.internal.model.ServiceTest;
+import org.glassfish.jersey.server.ResourceConfig;
+import org.glassfish.jersey.test.JerseyTest;
+import org.junit.Test;
+
+import jakarta.ws.rs.core.Application;
+
+import static org.junit.Assert.assertEquals;
+
+public class DefaultJsonJacksonProviderForBothModulesTest extends JerseyTest {
+    @Override
+    protected final Application configure() {
+        return new ResourceConfig(ServiceTest.class)
+                .property("jersey.config.json.jackson.enabled.modules", "Jdk8Module");
+    }
+
+    @Test
+    public final void testDisabledModule() {
+        final String response = target("entity/simple")
+                .request().get(String.class);
+
+        assertEquals("{\"name\":\"Hello\",\"value\":\"World\"}", response);
+    }
+
+}
diff --git a/media/json-jackson/src/test/java/org/glassfish/jersey/jackson/internal/DefaultJsonJacksonProviderForDisabledModulesTest.java b/media/json-jackson/src/test/java/org/glassfish/jersey/jackson/internal/DefaultJsonJacksonProviderForDisabledModulesTest.java
new file mode 100644
index 0000000..a9a86e6
--- /dev/null
+++ b/media/json-jackson/src/test/java/org/glassfish/jersey/jackson/internal/DefaultJsonJacksonProviderForDisabledModulesTest.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2022 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.jackson.internal;
+
+import org.glassfish.jersey.CommonProperties;
+import org.glassfish.jersey.jackson.JacksonFeature;
+import org.glassfish.jersey.jackson.internal.jackson.jaxrs.json.JacksonJaxbJsonProvider;
+import org.glassfish.jersey.jackson.internal.model.JAXBServiceTest;
+import org.glassfish.jersey.jackson.internal.model.ServiceTest;
+import org.glassfish.jersey.server.ResourceConfig;
+import org.glassfish.jersey.test.JerseyTest;
+import org.junit.Test;
+
+import jakarta.annotation.PostConstruct;
+import jakarta.inject.Inject;
+import jakarta.ws.rs.core.Application;
+import jakarta.ws.rs.core.Configuration;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+
+public class DefaultJsonJacksonProviderForDisabledModulesTest extends JerseyTest {
+    @Override
+    protected final Application configure() {
+        return new ResourceConfig(ServiceTest.class, JAXBServiceTest.class)
+                .property("jersey.config.json.jackson.disabled.modules", "Jdk8Module");
+    }
+
+    @Test
+    public final void testDisabledModule() {
+        getClient()
+                .register(JacksonFeature.class)
+                .register(TestJacksonJaxbJsonProvider.class)
+                .property("jersey.config.json.jackson.disabled.modules", "Jdk8Module");
+        final String response = target("JAXBEntity")
+                .request().get(String.class);
+        assertNotEquals("{\"key\":\"key\",\"value\":\"value\"}", response);
+    }
+
+    private static class TestJacksonJaxbJsonProvider extends JacksonJaxbJsonProvider {
+
+        @Inject
+        private Configuration configuration;
+
+        @PostConstruct
+        public void checkModulesCount() {
+            final String disabledModules =
+                    CommonProperties.getValue(configuration.getProperties(),
+                            configuration.getRuntimeType(),
+                            CommonProperties.JSON_JACKSON_DISABLED_MODULES, String.class);
+            assertEquals("Jdk8Module", disabledModules);
+        }
+
+    }
+
+}
\ No newline at end of file
diff --git a/media/json-jackson/src/test/java/org/glassfish/jersey/jackson/internal/DefaultJsonJacksonProviderForEnabledModulesTest.java b/media/json-jackson/src/test/java/org/glassfish/jersey/jackson/internal/DefaultJsonJacksonProviderForEnabledModulesTest.java
new file mode 100644
index 0000000..b1d5e9d
--- /dev/null
+++ b/media/json-jackson/src/test/java/org/glassfish/jersey/jackson/internal/DefaultJsonJacksonProviderForEnabledModulesTest.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2022 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.jackson.internal;
+
+import org.glassfish.jersey.jackson.internal.model.ServiceTest;
+import org.glassfish.jersey.server.ResourceConfig;
+import org.glassfish.jersey.test.JerseyTest;
+import org.junit.Test;
+
+import jakarta.ws.rs.core.Application;
+
+import static org.junit.Assert.assertNotEquals;
+
+public class DefaultJsonJacksonProviderForEnabledModulesTest extends JerseyTest {
+    @Override
+    protected final Application configure() {
+        return new ResourceConfig(ServiceTest.class)
+                .property("jersey.config.json.jackson.enabled.modules", "jackson-module-kotlin");
+    }
+
+    @Test
+    public final void testDisabledModule() {
+        final String response = target("entity/simple")
+                .request().get(String.class);
+        assertNotEquals("{\"name\":\"Hello\",\"value\":\"World\"}", response);
+    }
+
+}
diff --git a/media/json-jackson/src/test/java/org/glassfish/jersey/jackson/internal/model/JAXBServiceTest.java b/media/json-jackson/src/test/java/org/glassfish/jersey/jackson/internal/model/JAXBServiceTest.java
new file mode 100644
index 0000000..ed312a3
--- /dev/null
+++ b/media/json-jackson/src/test/java/org/glassfish/jersey/jackson/internal/model/JAXBServiceTest.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2022 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.jackson.internal.model;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+import jakarta.ws.rs.GET;
+import jakarta.ws.rs.Path;
+import jakarta.ws.rs.Produces;
+import jakarta.ws.rs.core.MediaType;
+import javax.xml.bind.annotation.XmlRootElement;
+import java.util.Optional;
+
+@Path("JAXBEntity")
+public class JAXBServiceTest {
+    @GET
+    @Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
+    public SimpleEntity get() {
+        return new SimpleEntity("key", "value");
+    }
+
+    @XmlRootElement
+    public static class SimpleEntity {
+        @JsonProperty
+        private String key;
+
+        @JsonProperty
+        private String value;
+
+        public SimpleEntity() {
+            key = "key";
+            value = "value";
+        }
+        public SimpleEntity(String key, String value) {
+            this.key = key;
+            this.value = value;
+        }
+
+        public Optional<String> getKey() {
+            return Optional.ofNullable(key);
+        }
+
+        public Optional<String> getValue() {
+            return Optional.ofNullable(value);
+        }
+
+    }
+}
diff --git a/pom.xml b/pom.xml
index 5305302..1d8f553 100644
--- a/pom.xml
+++ b/pom.xml
@@ -2091,7 +2091,7 @@
         <jersey.version>${project.version}</jersey.version>
         <!-- asm is now source integrated - keeping this property to see the version -->
         <!-- see core-server/src/main/java/jersey/repackaged/asm/.. -->
-        <asm.version>9.2</asm.version>
+        <asm.version>9.3</asm.version>
         <bnd.plugin.version>2.3.6</bnd.plugin.version>
 
         <bouncycastle.version>1.68</bouncycastle.version>
@@ -2125,7 +2125,7 @@
         <hk2.config.version>6.0.0</hk2.config.version>
         <httpclient.version>4.5.13</httpclient.version>
         <httpclient5.version>5.1.2</httpclient5.version>
-        <jackson.version>2.13.0</jackson.version>
+        <jackson.version>2.13.3</jackson.version>
         <javassist.version>3.25.0-GA</javassist.version>
         <jboss.logging.version>3.3.0.Final</jboss.logging.version>
         <jersey1.version>1.19.3</jersey1.version>
diff --git a/tests/e2e-client/pom.xml b/tests/e2e-client/pom.xml
index 3890a59..1dce53c 100644
--- a/tests/e2e-client/pom.xml
+++ b/tests/e2e-client/pom.xml
@@ -186,6 +186,34 @@
 
     <profiles>
         <profile>
+            <id>JettyTestExclude</id>
+            <activation>
+                <jdk>1.8</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/client/connector/proxy/Proxy*Test.java</testExclude>
+                                    </testExcludes>
+                                </configuration>
+                                <goals>
+                                    <goal>testCompile</goal>
+                                </goals>
+                            </execution>
+                        </executions>
+                    </plugin>
+                </plugins>
+            </build>
+        </profile>
+        <profile>
             <id>jdk11+</id>
             <activation>
                 <jdk>[11,)</jdk>
diff --git a/tests/e2e-client/src/test/java/org/glassfish/jersey/tests/e2e/client/connector/proxy/ProxySelectorTest.java b/tests/e2e-client/src/test/java/org/glassfish/jersey/tests/e2e/client/connector/proxy/ProxySelectorTest.java
new file mode 100644
index 0000000..1741a66
--- /dev/null
+++ b/tests/e2e-client/src/test/java/org/glassfish/jersey/tests/e2e/client/connector/proxy/ProxySelectorTest.java
@@ -0,0 +1,159 @@
+/*
+ * Copyright (c) 2020, 2022 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2019 Banco do Brasil S/A. 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.connector.proxy;
+
+import org.eclipse.jetty.server.HttpChannel;
+import org.eclipse.jetty.server.Request;
+import org.eclipse.jetty.server.Server;
+import org.eclipse.jetty.server.handler.AbstractHandler;
+import org.glassfish.jersey.apache.connector.ApacheConnectorProvider;
+import org.glassfish.jersey.apache5.connector.Apache5ConnectorProvider;
+import org.glassfish.jersey.client.ClientConfig;
+import org.glassfish.jersey.client.spi.ConnectorProvider;
+import org.glassfish.jersey.jetty.connector.JettyConnectorProvider;
+import org.glassfish.jersey.netty.connector.NettyConnectorProvider;
+import org.junit.AfterClass;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
+import jakarta.ws.rs.ProcessingException;
+import jakarta.ws.rs.client.Client;
+import jakarta.ws.rs.client.ClientBuilder;
+import jakarta.ws.rs.client.WebTarget;
+import jakarta.ws.rs.core.Response;
+import java.lang.reflect.InvocationTargetException;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import static org.junit.Assert.assertEquals;
+
+/**
+ * Moved from jetty-connector
+ * @author Marcelo Rubim
+ */
+@RunWith(Parameterized.class)
+public class ProxySelectorTest {
+    private static final String NO_PASS = "no-pass";
+
+    @Parameterized.Parameters(name = "{index}: {0}")
+    public static List<Object[]> testData() {
+        return Arrays.asList(new Object[][]{
+//                {ApacheConnectorProvider.class},
+//                {Apache5ConnectorProvider.class},
+//                {JettyConnectorProvider.class},
+                {NettyConnectorProvider.class},
+        });
+    }
+
+    private final ConnectorProvider connectorProvider;
+
+    public ProxySelectorTest(Class<? extends ConnectorProvider> connectorProviderClass)
+            throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
+        this.connectorProvider = connectorProviderClass.getConstructor().newInstance();
+    }
+
+    protected void configureClient(ClientConfig config) {
+        config.connectorProvider(connectorProvider);
+    }
+
+    @Test
+    public void testGetNoPass() {
+        try (Response response = target("proxyTest").request().header(NO_PASS, 200).get()) {
+            assertEquals(200, response.getStatus());
+        }
+    }
+
+    @Test
+    public void testGet407() {
+        try (Response response = target("proxyTest").request().get()) {
+            assertEquals(407, response.getStatus());
+        } catch (ProcessingException pe) {
+            Assert.assertTrue(pe.getMessage().contains("407")); // netty
+        }
+    }
+
+    private static Server server;
+    @BeforeClass
+    public static void startFakeProxy() {
+        server = new Server(9997);
+        server.setHandler(new ProxyHandler());
+        try {
+            server.start();
+        } catch (Exception e) {
+
+        }
+
+        System.setProperty("http.proxyHost", "http://localhost");
+        System.setProperty("http.proxyPort", "9997");
+    }
+
+    @AfterClass
+    public static void tearDownProxy() {
+        try {
+            server.stop();
+        } catch (Exception e) {
+
+        } finally {
+            System.clearProperty("http.proxyHost");
+            System.clearProperty("http.proxyPort");
+        }
+    }
+
+    private static Client client;
+    @Before
+    public void beforeEach() {
+        ClientConfig config = new ClientConfig();
+        this.configureClient(config);
+        client = ClientBuilder.newClient(config);
+    }
+
+    private Client client() {
+        return client;
+    }
+
+    private WebTarget target(String path) {
+        // ProxySelector goes DIRECT to localhost, no matter the proxy
+        return client().target("http://eclipse.org:9998").path(path);
+    }
+
+    static class ProxyHandler extends AbstractHandler {
+        Set<HttpChannel> httpConnect = new HashSet<>();
+        @Override
+        public void handle(String target,
+                           Request baseRequest,
+                           HttpServletRequest request,
+                           HttpServletResponse response) {
+            if (request.getHeader(NO_PASS) != null) {
+                response.setStatus(Integer.parseInt(request.getHeader(NO_PASS)));
+            } else {
+                response.setStatus(407);
+                response.addHeader("Proxy-Authenticate", "Basic");
+            }
+
+            baseRequest.setHandled(true);
+        }
+    }
+}
diff --git a/tests/e2e-client/src/test/java/org/glassfish/jersey/tests/e2e/client/connector/proxy/ProxyTest.java b/tests/e2e-client/src/test/java/org/glassfish/jersey/tests/e2e/client/connector/proxy/ProxyTest.java
new file mode 100644
index 0000000..1ae437b
--- /dev/null
+++ b/tests/e2e-client/src/test/java/org/glassfish/jersey/tests/e2e/client/connector/proxy/ProxyTest.java
@@ -0,0 +1,199 @@
+/*
+ * Copyright (c) 2020, 2022 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2019 Banco do Brasil S/A. 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.connector.proxy;
+
+import org.eclipse.jetty.server.HttpChannel;
+import org.eclipse.jetty.server.Request;
+import org.eclipse.jetty.server.Server;
+import org.eclipse.jetty.server.handler.AbstractHandler;
+import org.glassfish.jersey.apache.connector.ApacheConnectorProvider;
+import org.glassfish.jersey.apache5.connector.Apache5ConnectorProvider;
+import org.glassfish.jersey.client.ClientConfig;
+import org.glassfish.jersey.client.ClientProperties;
+import org.glassfish.jersey.client.spi.ConnectorProvider;
+import org.glassfish.jersey.jetty.connector.JettyConnectorProvider;
+import org.glassfish.jersey.netty.connector.NettyConnectorProvider;
+import org.junit.AfterClass;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
+import jakarta.ws.rs.ProcessingException;
+import jakarta.ws.rs.client.Client;
+import jakarta.ws.rs.client.ClientBuilder;
+import jakarta.ws.rs.client.WebTarget;
+import jakarta.ws.rs.core.Response;
+import java.lang.reflect.InvocationTargetException;
+import java.nio.charset.Charset;
+import java.util.Arrays;
+import java.util.Base64;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import static org.junit.Assert.assertEquals;
+
+/**
+ * Moved from jetty-connector
+ * @author Marcelo Rubim
+ */
+@RunWith(Parameterized.class)
+public class ProxyTest {
+    private static final Charset CHARACTER_SET = Charset.forName("iso-8859-1");
+    private static final String PROXY_URI = "http://127.0.0.1:9997";
+    private static final String PROXY_USERNAME = "proxy-user";
+    private static final String PROXY_PASSWORD = "proxy-password";
+    private static final String NO_PASS = "no-pass";
+
+    @Parameterized.Parameters(name = "{index}: {0}")
+    public static List<Object[]> testData() {
+        return Arrays.asList(new Object[][]{
+                {ApacheConnectorProvider.class},
+                {Apache5ConnectorProvider.class},
+                {JettyConnectorProvider.class},
+                {NettyConnectorProvider.class},
+        });
+    }
+
+    private final ConnectorProvider connectorProvider;
+
+    public ProxyTest(Class<? extends ConnectorProvider> connectorProviderClass)
+            throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
+        this.connectorProvider = connectorProviderClass.getConstructor().newInstance();
+    }
+
+    protected void configureClient(ClientConfig config) {
+        config.connectorProvider(connectorProvider);
+    }
+
+    @Test
+    public void testGetNoPass() {
+        client().property(ClientProperties.PROXY_URI, ProxyTest.PROXY_URI);
+        try (Response response = target("proxyTest").request().header(NO_PASS, 200).get()) {
+            assertEquals(200, response.getStatus());
+        }
+    }
+
+    @Test
+    public void testGet407() {
+        client().property(ClientProperties.PROXY_URI, ProxyTest.PROXY_URI);
+        try (Response response = target("proxyTest").request().get()) {
+            assertEquals(407, response.getStatus());
+        } catch (ProcessingException pe) {
+            Assert.assertTrue(pe.getMessage().contains("407")); // netty
+        }
+    }
+
+    @Test
+    public void testGetSuccess() {
+        client().property(ClientProperties.PROXY_URI, ProxyTest.PROXY_URI);
+        client().property(ClientProperties.PROXY_USERNAME, ProxyTest.PROXY_USERNAME);
+        client().property(ClientProperties.PROXY_PASSWORD, ProxyTest.PROXY_PASSWORD);
+        Response response = target("proxyTest").request().get();
+        assertEquals(200, response.getStatus());
+    }
+
+    private static Server server;
+    @BeforeClass
+    public static void startFakeProxy() {
+        server = new Server(9997);
+        server.setHandler(new ProxyHandler());
+        try {
+            server.start();
+        } catch (Exception e) {
+
+        }
+    }
+
+    @AfterClass
+    public static void tearDownProxy() {
+        try {
+            server.stop();
+        } catch (Exception e) {
+
+        }
+    }
+
+    private static Client client;
+    @Before
+    public void beforeEach() {
+        ClientConfig config = new ClientConfig();
+        this.configureClient(config);
+        client = ClientBuilder.newClient(config);
+    }
+
+    private Client client() {
+        return client;
+    }
+
+    private WebTarget target(String path) {
+        return client().target("http://localhost:9998").path(path);
+    }
+
+    static class ProxyHandler extends AbstractHandler {
+        Set<HttpChannel> httpConnect = new HashSet<>();
+        @Override
+        public void handle(String target,
+                           Request baseRequest,
+                           HttpServletRequest request,
+                           HttpServletResponse response) {
+            if (request.getHeader(NO_PASS) != null) {
+                response.setStatus(Integer.parseInt(request.getHeader(NO_PASS)));
+            } else if (request.getHeader("Proxy-Authorization") != null) {
+                String proxyAuthorization = request.getHeader("Proxy-Authorization");
+                String decoded = new String(Base64.getDecoder().decode(proxyAuthorization.substring(6).getBytes()),
+                        CHARACTER_SET);
+                final String[] split = decoded.split(":");
+                final String username = split[0];
+                final String password = split[1];
+
+                if (!username.equals(PROXY_USERNAME)) {
+                    response.setStatus(400);
+                    System.out.println("Found unexpected username: " + username);
+                }
+
+                if (!password.equals(PROXY_PASSWORD)) {
+                    response.setStatus(400);
+                    System.out.println("Found unexpected password: " + username);
+                }
+
+                if (response.getStatus() != 400) {
+                    response.setStatus(200);
+                    if ("CONNECT".equalsIgnoreCase(baseRequest.getMethod())) { // NETTY way of doing proxy
+                        httpConnect.add(baseRequest.getHttpChannel());
+                    }
+                }
+                //TODO Add redirect to requestURI
+            } else {
+                if (httpConnect.contains(baseRequest.getHttpChannel())) {
+                    response.setStatus(200);
+                } else {
+                    response.setStatus(407);
+                    response.addHeader("Proxy-Authenticate", "Basic");
+                }
+            }
+
+            baseRequest.setHandled(true);
+        }
+    }
+}
diff --git a/tests/integration/servlet-2.5-reload/pom.xml b/tests/integration/servlet-2.5-reload/pom.xml
index 32d8cf6..dbafe7f 100644
--- a/tests/integration/servlet-2.5-reload/pom.xml
+++ b/tests/integration/servlet-2.5-reload/pom.xml
@@ -55,10 +55,10 @@
                 <groupId>org.apache.maven.plugins</groupId>
                 <artifactId>maven-failsafe-plugin</artifactId>
             </plugin>
-            <plugin>
+            <!-- TODO: fix after 2.36 <plugin>
               <groupId>org.eclipse.jetty</groupId>
               <artifactId>jetty-maven-plugin</artifactId>
-            </plugin>
+            </plugin>-->
         </plugins>
     </build>
 
diff --git a/tests/integration/servlet-2.5-reload/src/test/java/org/glassfish/jersey/tests/integration/servlet_25_config_reload/ReloadTestIT.java b/tests/integration/servlet-2.5-reload/src/test/java/org/glassfish/jersey/tests/integration/servlet_25_config_reload/ReloadTestIT.java
index 313a319..bc57a0e 100644
--- a/tests/integration/servlet-2.5-reload/src/test/java/org/glassfish/jersey/tests/integration/servlet_25_config_reload/ReloadTestIT.java
+++ b/tests/integration/servlet-2.5-reload/src/test/java/org/glassfish/jersey/tests/integration/servlet_25_config_reload/ReloadTestIT.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2020 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2022 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
@@ -24,6 +24,7 @@
 import org.glassfish.jersey.test.spi.TestContainerException;
 import org.glassfish.jersey.test.spi.TestContainerFactory;
 
+import org.junit.Ignore;
 import org.junit.Test;
 
 import static org.junit.Assert.assertEquals;
@@ -44,6 +45,7 @@
     }
 
     @Test
+    @Ignore //TODO - fix after 2.36
     public void testReload() throws Exception {
         Response response = target().path("helloworld").request().get();
         assertEquals(200, response.getStatus());