The getter in TransportHandlingSockJsService now returns a mutable
List. The immutable wrapper doesn't make sense since it's possible
anyway to modify the list by creating a new list and calling the
setter again. It's also consistent with the same field on
WebSocketHttpRequestHandler.
This is related to work for SPR-12845.
This change adds support for global @MessageExceptionHandler methods
with STOMP over WebSocket messages. Such methods can be added to
@ControllerAdvice annotated components, much like @ExceptionHandler
methods for Spring MVC.
Issue: SPR-12696
WebSocketStompClient can be used with any implementation of
org.springframework.web.socket.client.WebSocketClient, which includes
org.springframework.web.socket.sockjs.client.SockJsClient.
Reactor11TcpStompClient can be used with reactor-net and provides STOMP
over TCP. It's also possible to adapt other WebSocket and TCP client
libraries (see StompClientSupport for more details).
For example usage see WebSocketStompClientIntegrationTests.
Issue: SPR-11588
This commit adds support for a same origin check that compares
Origin header to Host header. It also changes the default setting
from all origins allowed to only same origin allowed.
Issues: SPR-12697, SPR-12685
Before this change the WebSocketTransportHandler passed
Collections.emptyMap as attributes to the HandshakeHandler because
it didn't matter what attributes the underlying WebSocketSession has
since it is wrapped by the SockJsSession and that's what exposed for
use everywhere.
This change has the WebSocketTransportHandler passing the attributes
from the SockJsSession instead since it's more accurate for the
underlying WebSocketSession to have access to the same map instance
and it allows the HandshakeHandler to change the attributes even if
it doesn't need to do that today.
Issue: SPR-12716
Add support for annotation-based event listeners. Enabled automatically
when using Java configuration or can be enabled explicitly via the
regular <context:annotation-driven/> XML element. Detect methods of
managed beans annotated with @EventListener, either directly or through
a meta-annotation.
Annotated methods must define the event type they listen to as a single
parameter argument. Events are automatically filtered out according to
the method signature. When additional runtime filtering is required, one
can specify the `condition` attribute of the annotation that defines a
SpEL expression that should match to actually invoke the method for a
particular event. The root context exposes the actual `event`
(`#root.event`) and method arguments (`#root.args`). Individual method
arguments are also exposed via either the `a` or `p` alias (`#a0` refers
to the first method argument). Finally, methods arguments are exposed via
their names if that information can be discovered.
Events can be either an ApplicationEvent or any arbitrary payload. Such
payload is wrapped automatically in a PayloadApplicationEvent and managed
explicitly internally. As a result, users can now publish and listen
for arbitrary objects.
If an annotated method has a return value, an non null result is actually
published as a new event, something like:
@EventListener
public FooEvent handle(BarEvent event) { ... }
Events can be handled in an aynchronous manner by adding `@Async` to the
event method declaration and enabling such infrastructure. Events can
also be ordered by adding an `@Order` annotation to the event method.
Issue: SPR-11622
This commit introduces the following changes:
- Requests without Origin header are not rejected anymore
- Disable Iframe when allowedOrigins is not empty and not equals to *
- The Iframe is not cached anymore in order to have a reliable origin check
- allowedOrigins must not be null or empty
- allowedOrigins format is now validated (should be * or start by http(s)://)
Issue: SPR-12660
A logical follow-up on commit 43d937, this change also removes (or
rather deprecates for now) writePrelude that is only of concern to
streaming SockJS session implementations.
Issue: SPR-12427
This change removes the need for the isStreaming field from the base
class AbstractHttpSockJsSession. This field was used to account for
differences between polling vs streaming SockJS sessions without having
to expose to sub-classes private fields that are otherwise protected
from concurrent access by the base class. The change manages to delegate
to sub-classes without providing direct access to protected fields.
Issue: SPR-12427
This change designates Jetty SockJS integration tests to run as part of
the "performance", but not the main "publication", CI build due to
recurring low-level failures suspected to be Jetty issues, e.g.
"java.io.IOException: Cannot append to finished buffer" or
"java.io.IOException: Out of order Continuation frame encountered".
The tests will still run at once a day with the performance build but
should not fail the main build with false negatives. Also note that
an Undertow variant of the exact same tests, which hasn't been failing,
will continue to run as part of the main build.
The following two refinements have been added:
1) SockJS doesn't support binary messages so don't even try
2) don't bother if payload.length == 0
Issue: SPR-12475
This commit introduces the SpringHandlerInstantiator
class, a Jackson HandlerInstantiator that allows to autowire
Jackson handlers (JsonSerializer, JsonDeserializer, KeyDeserializer,
TypeResolverBuilder and TypeIdResolver) if needed.
SpringHandlerInstantiator is automatically used with
@EnableWebMvc and <mvc:annotation-driven />.
Issue: SPR-10768
With this commit, Jackson builder is now used in spring-websocket
to create the ObjectMapper instance.
It is not possible to use the builder for spring-messaging
and spring-jms since these modules don't have a dependency on
spring-web, thus they now just customize the same features:
- MapperFeature#DEFAULT_VIEW_INCLUSION is disabled
- DeserializationFeature#FAIL_ON_UNKNOWN_PROPERTIES is disabled
Issue: SPR-12293
Upgrade undertow dependency to 1.1.0.Final.
Add support for undertow 1.1.0.Final in the
UndertowRequestUpgradeStrategy, after a breaking change in the
`io.undertow.websockets.jsr.ConfiguredServerEndpoint` constructor.
Issue: SPR-12302
Prior to this change, duplicate SubProtocolHandlers could be registered
when configuring STOMP with several registrations:
public void registerStompEndpoints
(final StompEndpointRegistry registry) {
this.endpointRegistry.addEndpoint("/stompOverWebSocket");
this.endpointRegistry.addEndpoint("/stompOverSockJS").withSockJS();
}
This commit registers sub-protocols in a Set instead of a list (see
SubProtocolWebSocketHandler), thus fixing the issue.
Issue: SPR-12403
This commit introduces a new OriginHandshakeInterceptor. It filters
Origin header value against a list of allowed origins.
AbstractSockJsService as been modified to:
- Reject CORS requests with forbidden origins
- Disable transport types that does not support CORS when an origin
check is required
- Use the Origin request header value instead of "*" for
Access-Control-Allow-Origin response header value
(mandatory when Access-Control-Allow-Credentials=true)
- Return CORS header only if the request contains an Origin header
It is possible to configure easily this behavior thanks to JavaConfig API
WebSocketHandlerRegistration#addAllowedOrigins(String...) and
StompWebSocketEndpointRegistration#addAllowedOrigins(String...).
It is also possible to configure it using the websocket XML namespace.
Please notice that this commit does not change the default behavior:
cross origin requests are still enabled by default.
Issues: SPR-12226
Before this change the simple broker simply removed subscriptions
upon receiving a DISCONNECT message assuming it was a result of
a client STOMP WebSocket session ending.
However, if the server-side application sends a DISCONNECT to
the broker in order to terminate a session, the STOMP WebSocket
session could remain unware without any further action. This
change ensures the simple broker sends a DISCONNECT_ACK message
downstream whenever it receives a DISCONNECT.
Issue: SPR-12288
This change adds a ChannelInterceptor that flips the immutable flag on
messages being sent. This allows components sending messages to leave
the message mutable for interceptors to further apply modifications
before the message is sent (and exposed to concurrency).
The interceptor is automatically added with the STOMP/WebSocket Java
and XML config and the StompSubProtocolHandler leaves parsed incoming
messages mutable so they can be further modified before being sent.
Issue: SPR-12321