From 2339cc586a2dd7a4fd4b48d9dcaa4af0183f383e Mon Sep 17 00:00:00 2001 From: Pavel Ptashyts <49400901+pavel-ptashyts@users.noreply.github.com> Date: Sun, 19 Jul 2026 17:57:47 +0200 Subject: [PATCH] Avoid boxed redirect status lookup Replace the redirect status Set lookup with a primitive status-code helper in the response interceptor hot path. This removes the Redirect30xInterceptor.REDIRECT_STATUSES set and avoids boxing response codes before redirect handling. Add a unit test for the exact redirect and non-redirect status codes covered by the helper. Verified with:\n- /opt/maven/bin/mvn -pl client -DskipTests compile\n- /opt/maven/bin/mvn -pl client -Dtest=Redirect30xInterceptorTest,Relative302Test test --- .../netty/handler/intercept/Interceptors.java | 2 +- .../intercept/Redirect30xInterceptor.java | 20 +++++------ .../intercept/Redirect30xInterceptorTest.java | 35 +++++++++++++++++++ 3 files changed, 44 insertions(+), 13 deletions(-) create mode 100644 client/src/test/java/org/asynchttpclient/netty/handler/intercept/Redirect30xInterceptorTest.java diff --git a/client/src/main/java/org/asynchttpclient/netty/handler/intercept/Interceptors.java b/client/src/main/java/org/asynchttpclient/netty/handler/intercept/Interceptors.java index 5e12e2dfa..ef8d142d4 100644 --- a/client/src/main/java/org/asynchttpclient/netty/handler/intercept/Interceptors.java +++ b/client/src/main/java/org/asynchttpclient/netty/handler/intercept/Interceptors.java @@ -125,7 +125,7 @@ public boolean exitAfterIntercept(Channel channel, NettyResponseFuture future return continue100Interceptor.exitAfterHandling100(channel, future); } - if (Redirect30xInterceptor.REDIRECT_STATUSES.contains(statusCode)) { + if (Redirect30xInterceptor.isRedirectStatus(statusCode)) { return redirect30xInterceptor.exitAfterHandlingRedirect(channel, future, response, request, statusCode, realm); } diff --git a/client/src/main/java/org/asynchttpclient/netty/handler/intercept/Redirect30xInterceptor.java b/client/src/main/java/org/asynchttpclient/netty/handler/intercept/Redirect30xInterceptor.java index 189e78309..9793b9b46 100644 --- a/client/src/main/java/org/asynchttpclient/netty/handler/intercept/Redirect30xInterceptor.java +++ b/client/src/main/java/org/asynchttpclient/netty/handler/intercept/Redirect30xInterceptor.java @@ -35,9 +35,6 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.util.HashSet; -import java.util.Set; - import static io.netty.handler.codec.http.HttpHeaderNames.AUTHORIZATION; import static io.netty.handler.codec.http.HttpHeaderNames.CONTENT_LENGTH; import static io.netty.handler.codec.http.HttpHeaderNames.CONTENT_TYPE; @@ -59,17 +56,8 @@ public class Redirect30xInterceptor { - public static final Set REDIRECT_STATUSES = new HashSet<>(); private static final Logger LOGGER = LoggerFactory.getLogger(Redirect30xInterceptor.class); - static { - REDIRECT_STATUSES.add(MOVED_PERMANENTLY_301); - REDIRECT_STATUSES.add(FOUND_302); - REDIRECT_STATUSES.add(SEE_OTHER_303); - REDIRECT_STATUSES.add(TEMPORARY_REDIRECT_307); - REDIRECT_STATUSES.add(PERMANENT_REDIRECT_308); - } - private final ChannelManager channelManager; private final AsyncHttpClientConfig config; private final NettyRequestSender requestSender; @@ -203,6 +191,14 @@ public boolean exitAfterHandlingRedirect(Channel channel, NettyResponseFuture return false; } + static boolean isRedirectStatus(int statusCode) { + return statusCode == MOVED_PERMANENTLY_301 || + statusCode == FOUND_302 || + statusCode == SEE_OTHER_303 || + statusCode == TEMPORARY_REDIRECT_307 || + statusCode == PERMANENT_REDIRECT_308; + } + private static HttpHeaders propagatedHeaders(Request request, Realm realm, boolean keepBody, boolean stripAuthorization) { HttpHeaders headers = request.getHeaders() .remove(HOST) diff --git a/client/src/test/java/org/asynchttpclient/netty/handler/intercept/Redirect30xInterceptorTest.java b/client/src/test/java/org/asynchttpclient/netty/handler/intercept/Redirect30xInterceptorTest.java new file mode 100644 index 000000000..26a0298c7 --- /dev/null +++ b/client/src/test/java/org/asynchttpclient/netty/handler/intercept/Redirect30xInterceptorTest.java @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2026 AsyncHttpClient Project. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.asynchttpclient.netty.handler.intercept; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +public class Redirect30xInterceptorTest { + + @Test + public void primitiveRedirectStatusCheckMatchesRedirectStatuses() { + for (int statusCode : new int[]{301, 302, 303, 307, 308}) { + assertTrue(Redirect30xInterceptor.isRedirectStatus(statusCode), "status " + statusCode); + } + + for (int statusCode : new int[]{100, 200, 300, 304, 305, 306, 309, 400, 500}) { + assertFalse(Redirect30xInterceptor.isRedirectStatus(statusCode), "status " + statusCode); + } + } +}