Skip to content

Commit f8a82b4

Browse files
committed
Fix WebSocketHandlerMapping match for "/*"
Closes gh-34503
1 parent 057742f commit f8a82b4

File tree

3 files changed

+64
-29
lines changed

3 files changed

+64
-29
lines changed

spring-webmvc/src/main/java/org/springframework/web/servlet/handler/AbstractUrlHandlerMapping.java

+15-4
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,14 @@ public abstract class AbstractUrlHandlerMapping extends AbstractHandlerMapping i
7272

7373
private final Map<PathPattern, Object> pathPatternHandlerMap = new LinkedHashMap<>();
7474

75+
/**
76+
* Handler for "/*", to be checked after all other handlers.
77+
* Effectively similar to {@link #getDefaultHandler}, but processed at our level,
78+
* within {@link #getHandlerInternal} where the request is available.
79+
* @see org.springframework.web.socket.server.support.WebSocketHandlerMapping
80+
*/
81+
private @Nullable Object wildcardHandler;
82+
7583

7684
@Override
7785
public void setPatternParser(@Nullable PathPatternParser patternParser) {
@@ -166,9 +174,9 @@ public void registerHandler(String urlPath, Object handler) throws BeansExceptio
166174
}
167175
else if (urlPath.equals("/*")) {
168176
if (logger.isTraceEnabled()) {
169-
logger.trace("Default mapping to " + getHandlerDescription(handler));
177+
logger.trace("Wildcard mapping to " + getHandlerDescription(handler));
170178
}
171-
setDefaultHandler(resolvedHandler);
179+
this.wildcardHandler = resolvedHandler;
172180
}
173181
else {
174182
this.handlerMap.put(urlPath, resolvedHandler);
@@ -197,9 +205,9 @@ public void unregisterHandler(String urlPath) {
197205
}
198206
else if (urlPath.equals("/*")) {
199207
if (logger.isTraceEnabled()) {
200-
logger.trace("Removing default mapping: " + getDefaultHandler());
208+
logger.trace("Removing wildcard mapping: " + getDefaultHandler());
201209
}
202-
setDefaultHandler(null);
210+
this.wildcardHandler = null;
203211
}
204212
else {
205213
Object mappedHandler = this.handlerMap.get(urlPath);
@@ -248,6 +256,9 @@ private String getHandlerDescription(Object handler) {
248256
if (StringUtils.matchesCharacter(lookupPath, '/')) {
249257
rawHandler = getRootHandler();
250258
}
259+
if (rawHandler == null) {
260+
rawHandler = this.wildcardHandler;
261+
}
251262
if (rawHandler == null) {
252263
rawHandler = getDefaultHandler();
253264
}

spring-webmvc/src/test/java/org/springframework/web/servlet/handler/AbstractUrlHandlerMappingTests.java

+29-22
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2024 the original author or authors.
2+
* Copyright 2002-2025 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -23,6 +23,7 @@
2323
import org.junit.jupiter.api.Test;
2424

2525
import org.springframework.context.support.StaticApplicationContext;
26+
import org.springframework.web.testfixture.servlet.MockHttpServletRequest;
2627

2728
import static java.util.Map.entry;
2829
import static org.assertj.core.api.Assertions.assertThat;
@@ -45,10 +46,11 @@ void registerRootHandler() {
4546
}
4647

4748
@Test
48-
void registerDefaultHandler() {
49-
TestController defaultHandler = new TestController();
50-
mapping.registerHandler("/*", defaultHandler);
51-
assertThat(mapping).satisfies(hasMappings(null, defaultHandler, Map.of()));
49+
void registerWildcardHandler() throws Exception {
50+
TestController handler = new TestController();
51+
mapping.registerHandler("/*", handler);
52+
assertThat(mapping).satisfies(hasMappings(null, null, Map.of()));
53+
assertThat(getHandlerForPath("/abc")).isNotNull();
5254
}
5355

5456
@Test
@@ -70,43 +72,41 @@ void registerSpecificMappingWithBeanName() {
7072
@Test
7173
void unregisterRootHandler() {
7274
TestController rootHandler = new TestController();
73-
TestController defaultHandler = new TestController();
7475
TestController specificHandler = new TestController();
7576
mapping.registerHandler("/", rootHandler);
76-
mapping.registerHandler("/*", defaultHandler);
7777
mapping.registerHandler("/test", specificHandler);
78-
assertThat(mapping).satisfies(hasMappings(rootHandler, defaultHandler, Map.of("/test", specificHandler)));
78+
assertThat(mapping).satisfies(hasMappings(rootHandler, null, Map.of("/test", specificHandler)));
7979

8080
mapping.unregisterHandler("/");
81-
assertThat(mapping).satisfies(hasMappings(null, defaultHandler, Map.of("/test", specificHandler)));
81+
assertThat(mapping).satisfies(hasMappings(null, null, Map.of("/test", specificHandler)));
8282
}
8383

8484
@Test
85-
void unregisterDefaultHandler() {
86-
TestController rootHandler = new TestController();
87-
TestController defaultHandler = new TestController();
85+
void unregisterDefaultHandler() throws Exception {
86+
TestController wildcardHandler = new TestController();
8887
TestController specificHandler = new TestController();
89-
mapping.registerHandler("/", rootHandler);
90-
mapping.registerHandler("/*", defaultHandler);
88+
mapping.registerHandler("/*", wildcardHandler);
9189
mapping.registerHandler("/test", specificHandler);
92-
assertThat(mapping).satisfies(hasMappings(rootHandler, defaultHandler, Map.of("/test", specificHandler)));
90+
assertThat(mapping).satisfies(hasMappings(null, null, Map.of("/test", specificHandler)));
91+
assertThat(getHandlerForPath("/abc")).isNotNull();
9392

9493
mapping.unregisterHandler("/*");
95-
assertThat(mapping).satisfies(hasMappings(rootHandler, null, Map.of("/test", specificHandler)));
94+
assertThat(mapping).satisfies(hasMappings(null, null, Map.of("/test", specificHandler)));
95+
assertThat(getHandlerForPath("/abc")).isNull();
9696
}
9797

9898
@Test
9999
void unregisterSpecificHandler() {
100100
TestController rootHandler = new TestController();
101-
TestController defaultHandler = new TestController();
101+
TestController wildcardHandler = new TestController();
102102
TestController specificHandler = new TestController();
103103
mapping.registerHandler("/", rootHandler);
104-
mapping.registerHandler("/*", defaultHandler);
104+
mapping.registerHandler("/*", wildcardHandler);
105105
mapping.registerHandler("/test", specificHandler);
106-
assertThat(mapping).satisfies(hasMappings(rootHandler, defaultHandler, Map.of("/test", specificHandler)));
106+
assertThat(mapping).satisfies(hasMappings(rootHandler, null, Map.of("/test", specificHandler)));
107107

108108
mapping.unregisterHandler("/test");
109-
assertThat(mapping).satisfies(hasMappings(rootHandler, defaultHandler, Map.of()));
109+
assertThat(mapping).satisfies(hasMappings(rootHandler, null, Map.of()));
110110
}
111111

112112
@Test
@@ -129,15 +129,22 @@ void unregisterUnknownHandler() {
129129
}
130130

131131

132-
private Consumer<AbstractUrlHandlerMapping> hasMappings(@Nullable Object rootHandler,
133-
@Nullable Object defaultHandler, Map<String, Object> handlerMap) {
132+
private Consumer<AbstractUrlHandlerMapping> hasMappings(
133+
@Nullable Object rootHandler, @Nullable Object defaultHandler, Map<String, Object> handlerMap) {
134+
134135
return actual -> {
135136
assertThat(actual.getRootHandler()).isEqualTo(rootHandler);
136137
assertThat(actual.getDefaultHandler()).isEqualTo(defaultHandler);
137138
assertThat(actual.getHandlerMap()).containsExactlyEntriesOf(handlerMap);
138139
};
139140
}
140141

142+
private Object getHandlerForPath(String path) throws Exception {
143+
MockHttpServletRequest request = new MockHttpServletRequest("GET", path);
144+
return mapping.getHandlerInternal(request);
145+
}
146+
147+
141148
private static class TestController {}
142149

143150
}

spring-websocket/src/test/java/org/springframework/web/socket/server/support/WebSocketHandlerMappingTests.java

+20-3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2024 the original author or authors.
2+
* Copyright 2002-2025 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -16,7 +16,7 @@
1616

1717
package org.springframework.web.socket.server.support;
1818

19-
import java.util.Collections;
19+
import java.util.Map;
2020

2121
import org.junit.jupiter.api.Test;
2222

@@ -40,7 +40,7 @@ void webSocketHandshakeMatch() throws Exception {
4040
HttpRequestHandler handler = new WebSocketHttpRequestHandler(mock());
4141

4242
WebSocketHandlerMapping mapping = new WebSocketHandlerMapping();
43-
mapping.setUrlMap(Collections.singletonMap("/path", handler));
43+
mapping.setUrlMap(Map.of("/path", handler));
4444
mapping.setApplicationContext(new StaticWebApplicationContext());
4545

4646
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/path");
@@ -66,4 +66,21 @@ void webSocketHandshakeMatch() throws Exception {
6666
assertThat(chain).isNull();
6767
}
6868

69+
@Test // gh-34503
70+
void defaultHandler() throws Exception {
71+
HttpRequestHandler handler = new WebSocketHttpRequestHandler(mock());
72+
73+
WebSocketHandlerMapping mapping = new WebSocketHandlerMapping();
74+
mapping.setUrlMap(Map.of("/*", handler));
75+
mapping.setApplicationContext(new StaticWebApplicationContext());
76+
77+
assertThat(mapping.getDefaultHandler()).isNull();
78+
79+
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/path");
80+
HandlerExecutionChain chain = mapping.getHandler(request);
81+
82+
assertThat(chain).isNotNull();
83+
assertThat(chain.getHandler()).isSameAs(handler);
84+
}
85+
6986
}

0 commit comments

Comments
 (0)