I register a websocket with path '/*' and also called webSocketHandlerMapping.setWebSocketUpgradeMatch(true) in my program. When I send a common http request without Upgrade
header, WebSocketHandlerMapping aslo returned defaultHandler. I think webSocketUpgradeMatch should take effect for all handler include defaultHandler and getHandler() should return null when webSocketUpgradeMatch=true and no Upgrade
header present.
Comment From: rstoyanchev
The defaultHandler
is by design what we call when there is no match. It's not clear why you have it set, if you don't want it to be used?
Also, the webSocketUpgradeMatch
flag is in effect only for handlers of type WebSocketHttpRequestHandler
, i.e. where we know the intent is to handle the request as a WebSocket upgrade. So this wouldn't apply to the default handler unless it is also a WebSocketHttpRequestHandler
, which seems unlikely.
Comment From: cn19
I believe that logically, WebSocketHandlerMapping should only return handlers that meet the conditions, and webSocketUpgradeMatch, as a property of WebSocketHandlerMapping, should apply to all returned handlers.
In my program, I added a WebSocketHandler with the path set to "/*" and webSocketUpgradeMatch set to true. After starting the application, Spring Boot added the defaultHandler for WebSocketHandlerMapping. However, when handling a regular HTTP request (without the Upgrade header), the defaultHandler was returned. I think WebSocketHandlerMapping should return null in this case, allowing the process to proceed to the next WebSocketHandlerMapping or return a 404 status.
Comment From: rstoyanchev
defaultHandler is meant to use as a fallback option, to send an alternative response when the request doesn't match to the expected URL paths. If you mean to start a WebSocket connection regardless of the URL path, then just map the handler to "/*" rather than relying on a default handler, especially if that's the same handler.
In any case, there is no easy way to do what you're requesting since the overriding getDefaultHandler
does not provide access to the request.
Comment From: cn19
I am indeed registering the handler on the "/" path, and then Spring treats it as the defaultHandler. In other words, Spring considers "/" as the defaultHandler and does not perform any other condition matching.
org.springframework.web.servlet.handler.AbstractUrlHandlerMapping#registerHandler(java.lang.String, java.lang.Object)
Object mappedHandler = this.handlerMap.get(urlPath);
if (mappedHandler != null) {
if (mappedHandler != resolvedHandler) {
throw new IllegalStateException(
"Cannot map " + getHandlerDescription(handler) + " to URL path [" + urlPath +
"]: There is already " + getHandlerDescription(mappedHandler) + " mapped.");
}
}
else {
if (urlPath.equals("/")) {
if (logger.isTraceEnabled()) {
logger.trace("Root mapping to " + getHandlerDescription(handler));
}
setRootHandler(resolvedHandler);
}
else if (urlPath.equals("/*")) {
if (logger.isTraceEnabled()) {
logger.trace("Default mapping to " + getHandlerDescription(handler));
}
setDefaultHandler(resolvedHandler);
}
else {
this.handlerMap.put(urlPath, resolvedHandler);
if (getPatternParser() != null) {
this.pathPatternHandlerMap.put(getPatternParser().parse(urlPath), resolvedHandler);
}
if (logger.isTraceEnabled()) {
logger.trace("Mapped [" + urlPath + "] onto " + getHandlerDescription(handler));
}
}
}
Comment From: rstoyanchev
That's a good point. The treatment of "/*"
as a default handler ends up preventing WebSocketHandlerMapping from doing what it's trying to do.