Skip to content

Commit 285182b

Browse files
committed
Relax multiple segment matching constraints in PathPattern
Prior to this commit, gh-35213 allowed wildcard path elments at the start of path patterns. This came with an additional constraint that rejected such patterns if the pattern segment following the wildcard one was not a literal: * `/**/{name}` was rejected * `/**/something/{name}` was accepted The motivation here was to make the performance impact of wildard patterns as small as possible at runtime. This commit relaxes this constraint because `/**/*.js` patterns are very popular in the security space for request matchers. Closes gh-35686
1 parent 8bb6308 commit 285182b

File tree

5 files changed

+10
-27
lines changed

5 files changed

+10
-27
lines changed

framework-docs/modules/ROOT/partials/web/uri-patterns.adoc

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,6 @@
2626

2727
`+"/resources/**/file.png"+` is invalid as `+**+` is not allowed in the middle of the path.
2828

29-
`+"/**/{name}/resources"+` is invalid as only a literal pattern is allowed right after `+**+`.
30-
`+"/**/project/{project}/resources"+` is allowed.
31-
3229
`+"/**/spring/**"+` is not allowed, as only a single `+**+`/`+{*path}+` instance is allowed per pattern.
3330

3431
| `+{name}+`
@@ -49,9 +46,6 @@
4946

5047
`+"/resources/{*path}/file.png"+` is invalid as `{*path}` is not allowed in the middle of the path.
5148

52-
`+"/{*path}/{name}/resources"+` is invalid as only a literal pattern is allowed right after `{*path}`.
53-
`+"/{*path}/project/{project}/resources"+` is allowed.
54-
5549
`+"/{*path}/spring/**"+` is not allowed, as only a single `+**+`/`+{*path}+` instance is allowed per pattern.
5650

5751
|===

spring-web/src/main/java/org/springframework/web/util/pattern/InternalPathPatternParser.java

Lines changed: 0 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -185,7 +185,6 @@ else if ((this.pos > (this.variableCaptureStart + 1 + (this.isCaptureSegmentsVar
185185
if (this.pathElementStart != -1) {
186186
pushPathElement(createPathElement());
187187
}
188-
verifyPatternElements(this.headPE);
189188
return new PathPattern(pathPattern, this.parser, this.headPE);
190189
}
191190

@@ -441,22 +440,4 @@ private void recordCapturedVariable(int pos, String variableName) {
441440
this.capturedVariableNames.add(variableName);
442441
}
443442

444-
private void verifyPatternElements(@Nullable PathElement headPE) {
445-
PathElement currentElement = headPE;
446-
while (currentElement != null) {
447-
if (currentElement instanceof CaptureSegmentsPathElement ||
448-
currentElement instanceof WildcardSegmentsPathElement) {
449-
PathElement nextElement = currentElement.next;
450-
while (nextElement instanceof SeparatorPathElement) {
451-
nextElement = nextElement.next;
452-
}
453-
if (nextElement != null && !(nextElement instanceof LiteralPathElement)) {
454-
throw new PatternParseException(nextElement.pos, this.pathPatternData,
455-
PatternMessage.MULTISEGMENT_PATHELEMENT_NOT_FOLLOWED_BY_LITERAL);
456-
}
457-
}
458-
currentElement = currentElement.next;
459-
}
460-
}
461-
462443
}

spring-web/src/main/java/org/springframework/web/util/pattern/PatternParseException.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,6 @@ public enum PatternMessage {
101101
ILLEGAL_CHARACTER_IN_CAPTURE_DESCRIPTOR("Char ''{0}'' is not allowed in a captured variable name"),
102102
CANNOT_HAVE_MANY_MULTISEGMENT_PATHELEMENTS("Multiple '{*...}' or '**' pattern elements are not allowed"),
103103
INVALID_LOCATION_FOR_MULTISEGMENT_PATHELEMENT("'{*...}' or '**' pattern elements should be placed at the start or end of the pattern"),
104-
MULTISEGMENT_PATHELEMENT_NOT_FOLLOWED_BY_LITERAL("'{*...}' or '**' pattern elements should be followed by a literal path element"),
105104
BADLY_FORMED_CAPTURE_THE_REST("Expected form when capturing the rest of the path is simply '{*...}'"),
106105
MISSING_REGEX_CONSTRAINT("Missing regex constraint on capture"),
107106
ILLEGAL_DOUBLE_CAPTURE("Not allowed to capture ''{0}'' twice in the same pattern"),

spring-web/src/test/java/org/springframework/web/util/pattern/PathPatternParserTests.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -232,7 +232,6 @@ void captureSegmentsIllegalSyntax() {
232232
checkError("/{abc}{*foobar}", 1, PatternMessage.CAPTURE_ALL_IS_STANDALONE_CONSTRUCT);
233233
checkError("/{abc}{*foobar}{foo}", 1, PatternMessage.CAPTURE_ALL_IS_STANDALONE_CONSTRUCT);
234234
checkError("/{*foo}/foo/{*bar}", 18, PatternMessage.CANNOT_HAVE_MANY_MULTISEGMENT_PATHELEMENTS);
235-
checkError("/{*foo}/{bar}", 8, PatternMessage.MULTISEGMENT_PATHELEMENT_NOT_FOLLOWED_BY_LITERAL);
236235
checkError("{foo:}", 5, PatternMessage.MISSING_REGEX_CONSTRAINT);
237236
checkError("{foo}_{foo}", 0, PatternMessage.ILLEGAL_DOUBLE_CAPTURE, "foo");
238237
checkError("/{bar}/{bar}", 7, PatternMessage.ILLEGAL_DOUBLE_CAPTURE, "bar");

spring-web/src/test/java/org/springframework/web/util/pattern/PathPatternTests.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,16 @@ void wildcardSegmentsEnd() {
185185
checkMatches("/resource/**", "/resource/foobar");
186186
}
187187

188+
@Test
189+
void wildcardSegmentsThenNonLiteral() {
190+
checkMatches("/**/*.js", "/script.js");
191+
checkMatches("/**/*.js", "/js/script.js");
192+
checkMatches("/**/*.js", "/files/js/script.js");
193+
checkMatches("/**/{type}/*.js", "/files/js/script.js");
194+
195+
checkNoMatch("/**/*.js", "/files/style.css");
196+
}
197+
188198
@Test
189199
void antPathMatcherTests() {
190200
// test exact matching

0 commit comments

Comments
 (0)