Skip to content

Commit 4c8d336

Browse files
authored
Merge pull request #50384 from TomasHofman/issue-50330
Fix handling of overlapping paths in resteasy-reactive server
2 parents bd2ac5e + 2535096 commit 4c8d336

File tree

3 files changed

+72
-14
lines changed

3 files changed

+72
-14
lines changed

independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/mapping/PathMatcher.java

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package org.jboss.resteasy.reactive.server.mapping;
22

3+
import java.util.ArrayList;
34
import java.util.Comparator;
45
import java.util.List;
56
import java.util.Set;
@@ -34,24 +35,28 @@ class PathMatcher<T> implements Dumpable {
3435
* @param path The relative path to match
3536
* @return The match match. This will never be null, however if none matched its value field will be
3637
*/
37-
PathMatch<T> match(String path) {
38+
List<PathMatch<T>> match(String path) {
3839
int length = path.length();
3940
final int[] lengths = this.lengths;
41+
ArrayList<PathMatch<T>> matches = new ArrayList<>(1);
4042
for (int i = 0; i < lengths.length; ++i) {
4143
int pathLength = lengths[i];
4244
if (pathLength == length) {
4345
SubstringMap.SubstringMatch<T> next = paths.get(path, length);
4446
if (next != null) {
45-
return new PathMatch<>(path, "", next.getValue());
47+
matches.add(new PathMatch<>(path, "", next.getValue()));
4648
}
4749
} else if (pathLength < length) {
4850
SubstringMap.SubstringMatch<T> next = paths.get(path, pathLength);
4951
if (next != null) {
50-
return new PathMatch<>(next.getKey(), path.substring(pathLength), next.getValue());
52+
matches.add(new PathMatch<>(next.getKey(), path.substring(pathLength), next.getValue()));
5153
}
5254
}
5355
}
54-
return defaultMatch(path);
56+
if (matches.isEmpty()) {
57+
matches.add(defaultMatch(path));
58+
}
59+
return matches;
5560
}
5661

5762
PathMatch<T> defaultMatch(String path) {

independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/mapping/RequestMapper.java

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import java.util.Arrays;
55
import java.util.Collections;
66
import java.util.HashMap;
7+
import java.util.List;
78
import java.util.Map;
89
import java.util.function.BiConsumer;
910
import java.util.regex.Matcher;
@@ -48,9 +49,12 @@ public void accept(String stem, ArrayList<RequestPath<T>> list) {
4849
* @return best RequestMatch, or null if the path has no match
4950
*/
5051
public RequestMatch<T> map(String path) {
51-
var result = mapFromPathMatcher(path, requestPaths.match(path), 0);
52-
if (result != null) {
53-
return result;
52+
List<PathMatcher.PathMatch<ArrayList<RequestPath<T>>>> matches = requestPaths.match(path);
53+
for (int i = 0; i < matches.size(); i++) {
54+
var result = mapFromPathMatcher(path, matches.get(i), 0);
55+
if (result != null) {
56+
return result;
57+
}
5458
}
5559

5660
// the following code is meant to handle cases like https://github.com/quarkusio/quarkus/issues/30667
@@ -68,16 +72,21 @@ public RequestMatch<T> continueMatching(String path, RequestMatch<T> lastMatch)
6872
return null;
6973
}
7074

71-
var initialMatches = requestPaths.match(path);
72-
var result = mapFromPathMatcher(path, initialMatches, 0);
73-
if (result != null) {
74-
int idx = nextMatchStartingIndex(initialMatches, lastMatch);
75-
return mapFromPathMatcher(path, initialMatches, idx);
75+
var initialMatchesList = requestPaths.match(path);
76+
for (int i = 0; i < initialMatchesList.size(); i++) {
77+
var result = mapFromPathMatcher(path, initialMatchesList.get(i), 0);
78+
if (result != null) {
79+
int idx = nextMatchStartingIndex(initialMatchesList.get(i), lastMatch);
80+
RequestMatch<T> match = mapFromPathMatcher(path, initialMatchesList.get(i), idx);
81+
if (match != null) {
82+
return match;
83+
}
84+
}
7685
}
7786

7887
// the following code is meant to handle cases like https://github.com/quarkusio/quarkus/issues/30667
79-
initialMatches = requestPaths.defaultMatch(path);
80-
result = mapFromPathMatcher(path, initialMatches, 0);
88+
var initialMatches = requestPaths.defaultMatch(path);
89+
var result = mapFromPathMatcher(path, initialMatches, 0);
8190
if (result != null) {
8291
int idx = nextMatchStartingIndex(initialMatches, lastMatch);
8392
return mapFromPathMatcher(path, initialMatches, idx);

independent-projects/resteasy-reactive/server/vertx/src/test/java/org/jboss/resteasy/reactive/server/vertx/test/matching/PathParamOverlapTest.java

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,36 @@ public void test() {
5353
get("/hello/other/test/wrong")
5454
.then()
5555
.statusCode(404);
56+
57+
get("/hello/foo")
58+
.then()
59+
.statusCode(404);
60+
61+
get("/hello/foo/value")
62+
.then()
63+
.statusCode(200)
64+
.body(equalTo("Foo value"));
65+
66+
get("/hello/foo/bar")
67+
.then()
68+
.statusCode(200)
69+
.body(equalTo("Foo bar"));
70+
71+
get("/hello/foo/bar/value")
72+
.then()
73+
.statusCode(200)
74+
.body(equalTo("FooBar value"));
75+
76+
get("/hello/foo/bah_value")
77+
.then()
78+
.statusCode(200)
79+
.body(equalTo("Foo bah_value"));
80+
81+
get("/hello/foo/bar_value")
82+
.then()
83+
.statusCode(200)
84+
.body(equalTo("Foo bar_value"));
85+
5686
}
5787

5888
@Path("/hello")
@@ -70,5 +100,19 @@ public String test() {
70100
public String second(@RestPath String id) {
71101
return "Hello " + id;
72102
}
103+
104+
@GET
105+
@Path("/foo/{param}")
106+
public String foo(@RestPath String param) {
107+
return "Foo " + param;
108+
}
109+
110+
@GET
111+
@Path("/foo/bar/{param}")
112+
public String fooBar(@RestPath String param) {
113+
return "FooBar " + param;
114+
}
115+
73116
}
117+
74118
}

0 commit comments

Comments
 (0)