Skip to content

Commit 947950e

Browse files
authored
Merge pull request #4017 from spring-cloud/place-attributes-on-unwrapped-request
Unwrap request to put attributes on underlying request
2 parents ff64035 + 45962c0 commit 947950e

File tree

2 files changed

+28
-23
lines changed

2 files changed

+28
-23
lines changed

spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/common/MvcUtils.java

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@
3434
import java.util.Objects;
3535
import java.util.Optional;
3636

37+
import jakarta.servlet.http.HttpServletRequest;
38+
import jakarta.servlet.http.HttpServletRequestWrapper;
3739
import org.apache.commons.logging.Log;
3840
import org.apache.commons.logging.LogFactory;
3941
import org.jspecify.annotations.Nullable;
@@ -123,6 +125,21 @@ public static <T> Optional<T> cacheAndReadBody(ServerRequest request, Class<T> t
123125
return readBody(request, rawBody, toClass);
124126
}
125127

128+
/**
129+
* Unwraps an HttpServletRequest to get to the innermost request. This is necessary to
130+
* ensure attributes are set on the actual request object rather than on wrapper
131+
* instances that may not propagate attribute changes.
132+
* @param request the request to unwrap
133+
* @return the innermost HttpServletRequest
134+
*/
135+
private static HttpServletRequest unwrapRequest(HttpServletRequest request) {
136+
HttpServletRequest unwrapped = request;
137+
while (unwrapped instanceof HttpServletRequestWrapper wrapper) {
138+
unwrapped = (HttpServletRequest) wrapper.getRequest();
139+
}
140+
return unwrapped;
141+
}
142+
126143
public static ByteArrayInputStream cacheBody(ServerRequest request) {
127144
try {
128145
byte[] bytes = StreamUtils.copyToByteArray(request.servletRequest().getInputStream());
@@ -187,7 +204,12 @@ public static ApplicationContext getApplicationContext(ServerRequest request) {
187204
if (request.attributes().containsKey(key)) {
188205
return (T) request.attributes().get(key);
189206
}
190-
return (T) getGatewayAttributes(request).get(key);
207+
T gatewayAttr = (T) getGatewayAttributes(request).get(key);
208+
if (gatewayAttr != null) {
209+
return gatewayAttr;
210+
}
211+
// Fallback to servlet request attributes for compatibility with request wrappers
212+
return (T) request.servletRequest().getAttribute(key);
191213
}
192214

193215
@SuppressWarnings("unchecked")
@@ -211,13 +233,18 @@ public static Map<String, Object> getUriTemplateVariables(ServerRequest request)
211233
}
212234

213235
public static void putAttribute(ServerRequest request, String key, @Nullable Object value) {
236+
// Also set on the unwrapped servlet request to ensure persistence through
237+
// wrappers like Spring's AttributesPreservingRequest
238+
HttpServletRequest unwrapped = unwrapRequest((HttpServletRequest) request.servletRequest());
214239
if (value == null) {
215240
request.attributes().remove(key);
216241
getGatewayAttributes(request).remove(key);
242+
unwrapped.removeAttribute(key);
217243
}
218244
else {
219245
request.attributes().put(key, value);
220246
getGatewayAttributes(request).put(key, value);
247+
unwrapped.setAttribute(key, value);
221248
}
222249

223250
}

spring-cloud-gateway-server-webmvc/src/test/java/org/springframework/cloud/gateway/server/mvc/ServerMvcIntegrationTests.java

Lines changed: 0 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,6 @@
6565
import org.springframework.cloud.loadbalancer.annotation.LoadBalancerClient;
6666
import org.springframework.context.annotation.Bean;
6767
import org.springframework.context.annotation.Import;
68-
import org.springframework.context.annotation.Lazy;
6968
import org.springframework.core.Ordered;
7069
import org.springframework.core.io.ClassPathResource;
7170
import org.springframework.http.HttpEntity;
@@ -90,7 +89,6 @@
9089
import org.springframework.web.servlet.function.RouterFunction;
9190
import org.springframework.web.servlet.function.ServerRequest;
9291
import org.springframework.web.servlet.function.ServerResponse;
93-
import org.springframework.web.servlet.handler.HandlerMappingIntrospector;
9492

9593
import static org.assertj.core.api.Assertions.assertThat;
9694
import static org.springframework.cloud.gateway.server.mvc.filter.AfterFilterFunctions.DedupeStrategy.RETAIN_FIRST;
@@ -1048,26 +1046,6 @@ EventController eventController() {
10481046
return new EventController();
10491047
}
10501048

1051-
// TODO This is needed to work around
1052-
// https://github.com/spring-cloud/spring-cloud-gateway/issues/3816
1053-
// which results from Spring Security being on the classpath. Once we can address
1054-
// this issue we should
1055-
// remove this bean and no longer extend WebMvcConfigurationSupport in this
1056-
// configuration class
1057-
@Bean
1058-
@Lazy
1059-
@Override
1060-
public HandlerMappingIntrospector mvcHandlerMappingIntrospector() {
1061-
return new HandlerMappingIntrospector() {
1062-
@Override
1063-
public Filter createCacheFilter() {
1064-
return (request, response, chain) -> {
1065-
chain.doFilter(request, response);
1066-
};
1067-
}
1068-
};
1069-
}
1070-
10711049
@Bean
10721050
public AsyncProxyManager<String> caffeineProxyManager() {
10731051
Caffeine<String, RemoteBucketState> builder = (Caffeine) Caffeine.newBuilder().maximumSize(100);

0 commit comments

Comments
 (0)