diff --git a/spring-messaging/src/main/java/org/springframework/messaging/handler/invocation/HandlerMethodArgumentResolverComposite.java b/spring-messaging/src/main/java/org/springframework/messaging/handler/invocation/HandlerMethodArgumentResolverComposite.java index 7bde7fb3d3..966fa70834 100644 --- a/spring-messaging/src/main/java/org/springframework/messaging/handler/invocation/HandlerMethodArgumentResolverComposite.java +++ b/spring-messaging/src/main/java/org/springframework/messaging/handler/invocation/HandlerMethodArgumentResolverComposite.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2020 the original author or authors. + * Copyright 2002-2022 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -84,10 +84,11 @@ public class HandlerMethodArgumentResolverComposite implements HandlerMethodArgu } /** - * Clear the list of configured resolvers. + * Clear the list of configured resolvers and the resolver cache. */ public void clear() { this.argumentResolvers.clear(); + this.argumentResolverCache.clear(); } diff --git a/spring-messaging/src/main/java/org/springframework/messaging/handler/invocation/reactive/HandlerMethodArgumentResolverComposite.java b/spring-messaging/src/main/java/org/springframework/messaging/handler/invocation/reactive/HandlerMethodArgumentResolverComposite.java index 3009a05e56..fc73bf63de 100644 --- a/spring-messaging/src/main/java/org/springframework/messaging/handler/invocation/reactive/HandlerMethodArgumentResolverComposite.java +++ b/spring-messaging/src/main/java/org/springframework/messaging/handler/invocation/reactive/HandlerMethodArgumentResolverComposite.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2020 the original author or authors. + * Copyright 2002-2022 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -86,10 +86,11 @@ public class HandlerMethodArgumentResolverComposite implements HandlerMethodArgu } /** - * Clear the list of configured resolvers. + * Clear the list of configured resolvers and the resolver cache. */ public void clear() { this.argumentResolvers.clear(); + this.argumentResolverCache.clear(); } diff --git a/spring-web/src/main/java/org/springframework/http/server/reactive/AbstractServerHttpRequest.java b/spring-web/src/main/java/org/springframework/http/server/reactive/AbstractServerHttpRequest.java index c33ae2c3c0..3411a71264 100644 --- a/spring-web/src/main/java/org/springframework/http/server/reactive/AbstractServerHttpRequest.java +++ b/spring-web/src/main/java/org/springframework/http/server/reactive/AbstractServerHttpRequest.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2021 the original author or authors. + * Copyright 2002-2022 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -211,9 +211,18 @@ public abstract class AbstractServerHttpRequest implements ServerHttpRequest { */ String getLogPrefix() { if (this.logPrefix == null) { - this.logPrefix = "[" + getId() + "] "; + this.logPrefix = "[" + initLogPrefix() + "] "; } return this.logPrefix; } + /** + * Subclasses can override this to provide the prefix to use for log messages. + *

By default, this is {@link #getId()}. + * @since 5.3.15 + */ + protected String initLogPrefix() { + return getId(); + } + } diff --git a/spring-web/src/main/java/org/springframework/http/server/reactive/ReactorServerHttpRequest.java b/spring-web/src/main/java/org/springframework/http/server/reactive/ReactorServerHttpRequest.java index ad809acf01..24ab5c92a2 100644 --- a/spring-web/src/main/java/org/springframework/http/server/reactive/ReactorServerHttpRequest.java +++ b/spring-web/src/main/java/org/springframework/http/server/reactive/ReactorServerHttpRequest.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2021 the original author or authors. + * Copyright 2002-2022 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -78,7 +78,7 @@ class ReactorServerHttpRequest extends AbstractServerHttpRequest { private static URI initUri(HttpServerRequest request) throws URISyntaxException { Assert.notNull(request, "HttpServerRequest must not be null"); - return new URI(resolveBaseUrl(request).toString() + resolveRequestUri(request)); + return new URI(resolveBaseUrl(request) + resolveRequestUri(request)); } private static URI resolveBaseUrl(HttpServerRequest request) throws URISyntaxException { @@ -203,9 +203,6 @@ class ReactorServerHttpRequest extends AbstractServerHttpRequest { @Override @Nullable protected String initId() { - if (reactorNettyRequestChannelOperationsIdPresent) { - return (ChannelOperationsIdHelper.getId(this.request)); - } if (this.request instanceof Connection) { return ((Connection) this.request).channel().id().asShortText() + "-" + logPrefixIndex.incrementAndGet(); @@ -213,6 +210,21 @@ class ReactorServerHttpRequest extends AbstractServerHttpRequest { return null; } + @Override + protected String initLogPrefix() { + if (reactorNettyRequestChannelOperationsIdPresent) { + String id = (ChannelOperationsIdHelper.getId(this.request)); + if (id != null) { + return id; + } + } + if (this.request instanceof Connection) { + return ((Connection) this.request).channel().id().asShortText() + + "-" + logPrefixIndex.incrementAndGet(); + } + return getId(); + } + private static class ChannelOperationsIdHelper { diff --git a/spring-web/src/main/java/org/springframework/http/server/reactive/ServerHttpResponseDecorator.java b/spring-web/src/main/java/org/springframework/http/server/reactive/ServerHttpResponseDecorator.java index 79a6c0c8bd..c6574c26f3 100644 --- a/spring-web/src/main/java/org/springframework/http/server/reactive/ServerHttpResponseDecorator.java +++ b/spring-web/src/main/java/org/springframework/http/server/reactive/ServerHttpResponseDecorator.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2021 the original author or authors. + * Copyright 2002-2022 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -65,6 +65,16 @@ public class ServerHttpResponseDecorator implements ServerHttpResponse { return getDelegate().getStatusCode(); } + @Override + public boolean setRawStatusCode(@Nullable Integer value) { + return getDelegate().setRawStatusCode(value); + } + + @Override + public Integer getRawStatusCode() { + return getDelegate().getRawStatusCode(); + } + @Override public HttpHeaders getHeaders() { return getDelegate().getHeaders(); diff --git a/spring-web/src/main/java/org/springframework/web/method/support/HandlerMethodArgumentResolverComposite.java b/spring-web/src/main/java/org/springframework/web/method/support/HandlerMethodArgumentResolverComposite.java index 60a27b9ae5..e9b5f6056c 100644 --- a/spring-web/src/main/java/org/springframework/web/method/support/HandlerMethodArgumentResolverComposite.java +++ b/spring-web/src/main/java/org/springframework/web/method/support/HandlerMethodArgumentResolverComposite.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2020 the original author or authors. + * Copyright 2002-2022 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -85,11 +85,12 @@ public class HandlerMethodArgumentResolverComposite implements HandlerMethodArgu } /** - * Clear the list of configured resolvers. + * Clear the list of configured resolvers and the resolver cache. * @since 4.3 */ public void clear() { this.argumentResolvers.clear(); + this.argumentResolverCache.clear(); } diff --git a/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/HandlerMethodArgumentResolverComposite.java b/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/HandlerMethodArgumentResolverComposite.java index 46baa13c5f..351badb98e 100644 --- a/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/HandlerMethodArgumentResolverComposite.java +++ b/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/HandlerMethodArgumentResolverComposite.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2020 the original author or authors. + * Copyright 2002-2022 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -83,10 +83,11 @@ class HandlerMethodArgumentResolverComposite implements HandlerMethodArgumentRes } /** - * Clear the list of configured resolvers. + * Clear the list of configured resolvers and the resolver cache. */ public void clear() { this.argumentResolvers.clear(); + this.argumentResolverCache.clear(); } diff --git a/src/docs/asciidoc/web/websocket.adoc b/src/docs/asciidoc/web/websocket.adoc index 4b80a9eada..667168be98 100644 --- a/src/docs/asciidoc/web/websocket.adoc +++ b/src/docs/asciidoc/web/websocket.adoc @@ -1724,19 +1724,11 @@ HTTP session (which is then associated with WebSocket or SockJS sessions created for that user) and results in a user header being stamped on every `Message` flowing through the application. -Note that the STOMP protocol does have `login` and `passcode` headers -on the `CONNECT` frame. Those were originally designed for and are still needed, -for example, for STOMP over TCP. However, for STOMP over WebSocket, by default, -Spring ignores authorization headers at the STOMP protocol level, assumes that -the user is already authenticated at the HTTP transport level, and expects that -the WebSocket or SockJS session contain the authenticated user. - -NOTE: Spring Security provides -https://docs.spring.io/spring-security/reference/servlet/integrations/websocket.html#websocket-authorization[WebSocket sub-protocol authorization] -that uses a `ChannelInterceptor` to authorize messages based on the user header in them. -Also, Spring Session provides -https://docs.spring.io/spring-session/reference/web-socket.html[WebSocket integration] -that ensures the user's HTTP session does not expire while the WebSocket session is still active. +The STOMP protocol does have `login` and `passcode` headers on the `CONNECT` frame. +Those were originally designed for and are needed for STOMP over TCP. However, for STOMP +over WebSocket, by default, Spring ignores authentication headers at the STOMP protocol +level, and assumes that the user is already authenticated at the HTTP transport level. +The expectation is that the WebSocket or SockJS session contain the authenticated user. @@ -1814,6 +1806,18 @@ its own implementation of `WebSocketMessageBrokerConfigurer` that is marked with +[[websocket-stomp-authorization]] +=== Authorization + +Spring Security provides +https://docs.spring.io/spring-security/reference/servlet/integrations/websocket.html#websocket-authorization[WebSocket sub-protocol authorization] +that uses a `ChannelInterceptor` to authorize messages based on the user header in them. +Also, Spring Session provides +https://docs.spring.io/spring-session/reference/web-socket.html[WebSocket integration] +that ensures the user's HTTP session does not expire while the WebSocket session is still active. + + + [[websocket-stomp-user-destination]] === User Destinations