This is an automated email from the ASF dual-hosted git repository.
markt-asf pushed a commit to branch 10.1.x
in repository https://gitbox.apache.org/repos/asf/tomcat.git
The following commit(s) were added to refs/heads/10.1.x by this push:
new 6c5a93fce1 Stricter URI template matching for WebSocket
6c5a93fce1 is described below
commit 6c5a93fce14a45e2a3bbfe4c464c0385df81ff9b
Author: Mark Thomas <[email protected]>
AuthorDate: Mon Jul 27 16:27:34 2026 +0100
Stricter URI template matching for WebSocket
---
.../websocket/server/LocalStrings.properties | 1 -
.../websocket/server/LocalStrings_fr.properties | 1 -
.../websocket/server/LocalStrings_ja.properties | 1 -
.../websocket/server/LocalStrings_ko.properties | 1 -
.../websocket/server/LocalStrings_zh_CN.properties | 1 -
.../tomcat/websocket/server/UriTemplate.java | 13 ++--
.../tomcat/websocket/server/TestUriTemplate.java | 78 ++++++++++------------
webapps/docs/changelog.xml | 7 ++
8 files changed, 48 insertions(+), 55 deletions(-)
diff --git a/java/org/apache/tomcat/websocket/server/LocalStrings.properties
b/java/org/apache/tomcat/websocket/server/LocalStrings.properties
index 1e473f3d8c..0587733b41 100644
--- a/java/org/apache/tomcat/websocket/server/LocalStrings.properties
+++ b/java/org/apache/tomcat/websocket/server/LocalStrings.properties
@@ -27,7 +27,6 @@ upgradeUtil.incompatibleRsv=Extensions were specified that
have incompatible RSV
upgradeUtil.pojoMapFail=Unable to complete method mapping for POJO class [{0}]
uriTemplate.duplicateParameter=The parameter [{0}] appears more than once in
the path which is not permitted
-uriTemplate.emptySegment=The path [{0}] contains one or more empty segments
which is not permitted
uriTemplate.invalidPath=The path [{0}] is not valid.
uriTemplate.invalidSegment=The segment [{0}] is not valid in the provided path
[{1}]
diff --git a/java/org/apache/tomcat/websocket/server/LocalStrings_fr.properties
b/java/org/apache/tomcat/websocket/server/LocalStrings_fr.properties
index b963760cbc..8d2acb71b3 100644
--- a/java/org/apache/tomcat/websocket/server/LocalStrings_fr.properties
+++ b/java/org/apache/tomcat/websocket/server/LocalStrings_fr.properties
@@ -27,7 +27,6 @@ upgradeUtil.incompatibleRsv=Des extensions qui ont été
spécifiées ont une ut
upgradeUtil.pojoMapFail=Impossible de compléter le mappage des méthodes pour
la classe POJO [{0}]
uriTemplate.duplicateParameter=Le paramètre [{0}] apparaît plus d''une fois
dans le chemin ce qui n''est pas permis
-uriTemplate.emptySegment=Le chemin [{0}] contient un ou plusieurs segments
vide ce qui n''est pas autorisé
uriTemplate.invalidPath=Le chemin [{0}] est invalide
uriTemplate.invalidSegment=Le segment [{0}] est invalide pour le chemin fourni
[{1}]
diff --git a/java/org/apache/tomcat/websocket/server/LocalStrings_ja.properties
b/java/org/apache/tomcat/websocket/server/LocalStrings_ja.properties
index f63b542ab9..9ea5ad4b41 100644
--- a/java/org/apache/tomcat/websocket/server/LocalStrings_ja.properties
+++ b/java/org/apache/tomcat/websocket/server/LocalStrings_ja.properties
@@ -27,7 +27,6 @@ upgradeUtil.incompatibleRsv=互換性のないRSVビットの使用法を持つ
upgradeUtil.pojoMapFail=POJOクラス [{0}] のメソッドマッピングを完了できません
uriTemplate.duplicateParameter=パス内にパラメーター [{0}] を複数回登場させることはできません
-uriTemplate.emptySegment=パス [{0}] に一つ以上の空セグメントを含めることはできません。
uriTemplate.invalidPath=[{0}] は無効なパスです。
uriTemplate.invalidSegment=パス [{1}] に存在しないセグメント [{0}] が指定されました。
diff --git a/java/org/apache/tomcat/websocket/server/LocalStrings_ko.properties
b/java/org/apache/tomcat/websocket/server/LocalStrings_ko.properties
index 6bf78c110c..bc7f809b20 100644
--- a/java/org/apache/tomcat/websocket/server/LocalStrings_ko.properties
+++ b/java/org/apache/tomcat/websocket/server/LocalStrings_ko.properties
@@ -27,7 +27,6 @@ upgradeUtil.incompatibleRsv=호환되지 않는 RSV 비트를 사용하여, Exte
upgradeUtil.pojoMapFail=POJO 클래스 [{0}](을)를 위한 메소드 매핑을 완료할 수 없습니다.
uriTemplate.duplicateParameter=허용되지 않는 경로에서, 파라미터 [{0}]이(가) 두번 이상 나타나고 있습니다.
-uriTemplate.emptySegment=경로 [{0}]이(가), 하나 이상의 허용되지 않는 empty segment들을 포함하고
있습니다.
uriTemplate.invalidPath=경로 [{0}](은)는 유효하지 않습니다.
uriTemplate.invalidSegment=세그먼트 [{0}]은(는) 제공된 경로 [{1}] 내에 유효하지 않습니다.
diff --git
a/java/org/apache/tomcat/websocket/server/LocalStrings_zh_CN.properties
b/java/org/apache/tomcat/websocket/server/LocalStrings_zh_CN.properties
index 4c5c372eaf..090b3348dc 100644
--- a/java/org/apache/tomcat/websocket/server/LocalStrings_zh_CN.properties
+++ b/java/org/apache/tomcat/websocket/server/LocalStrings_zh_CN.properties
@@ -27,7 +27,6 @@ upgradeUtil.incompatibleRsv=指定扩展名具有不兼容的RSV位使用
upgradeUtil.pojoMapFail=无法完成 POJO 类 [{0}] 的方法映射
uriTemplate.duplicateParameter=参数[{0}]在不允许的路径中出现多次
-uriTemplate.emptySegment=路径[{0}]包含一个或多个不允许的空段
uriTemplate.invalidPath=路径 [{0}] 无效。
uriTemplate.invalidSegment=段[{0}]在提供的路径[{1}]中无效
diff --git a/java/org/apache/tomcat/websocket/server/UriTemplate.java
b/java/org/apache/tomcat/websocket/server/UriTemplate.java
index 030044692d..39571cde2a 100644
--- a/java/org/apache/tomcat/websocket/server/UriTemplate.java
+++ b/java/org/apache/tomcat/websocket/server/UriTemplate.java
@@ -65,16 +65,11 @@ public class UriTemplate {
for (int i = 0; i < segments.length; i++) {
String segment = segments[i];
if (segment.isEmpty()) {
- if (i == 0 || (i == segments.length - 1 && paramCount == 0)) {
- // Ignore the first empty segment as the path must always
- // start with '/'
- // Ending with a '/' is also OK for instances used for
- // matches but not for parameterised templates.
+ if (i == 0) {
+ // Ignore the first empty segment as the path must always
start with '/'.
continue;
- } else {
- // As per EG discussion, all other empty segments are
- // invalid
- throw new
DeploymentException(sm.getString("uriTemplate.emptySegment", path));
+ } else if (i == segments.length - 1) {
+ // Ending with a '/' is allowed.
}
}
normalized.append('/');
diff --git a/test/org/apache/tomcat/websocket/server/TestUriTemplate.java
b/test/org/apache/tomcat/websocket/server/TestUriTemplate.java
index b2071be3d3..6cc795be93 100644
--- a/test/org/apache/tomcat/websocket/server/TestUriTemplate.java
+++ b/test/org/apache/tomcat/websocket/server/TestUriTemplate.java
@@ -90,8 +90,8 @@ public class TestUriTemplate {
@Test
public void testSpecExample1_01() throws Exception {
- UriTemplate t = new UriTemplate("/a/b");
- Map<String, String> result = t.match(new UriTemplate("/a/b"));
+ UriTemplate t = new UriTemplate("/a/b/");
+ Map<String, String> result = t.match(new UriTemplate("/a/b/"));
Assert.assertEquals(0, result.size());
}
@@ -99,8 +99,8 @@ public class TestUriTemplate {
@Test
public void testSpecExample1_02() throws Exception {
- UriTemplate t = new UriTemplate("/a/b");
- Map<String, String> result = t.match(new UriTemplate("/a"));
+ UriTemplate t = new UriTemplate("/a/b/");
+ Map<String, String> result = t.match(new UriTemplate("/a/b"));
Assert.assertNull(result);
}
@@ -108,7 +108,16 @@ public class TestUriTemplate {
@Test
public void testSpecExample1_03() throws Exception {
- UriTemplate t = new UriTemplate("/a/b");
+ UriTemplate t = new UriTemplate("/a/b/");
+ Map<String, String> result = t.match(new UriTemplate("/a"));
+
+ Assert.assertNull(result);
+ }
+
+
+ @Test
+ public void testSpecExample1_04() throws Exception {
+ UriTemplate t = new UriTemplate("/a/b/");
Map<String, String> result = t.match(new UriTemplate("/a/bb"));
Assert.assertNull(result);
@@ -146,6 +155,15 @@ public class TestUriTemplate {
@Test
public void testSpecExample2_04() throws Exception {
+ UriTemplate t = new UriTemplate("/a/{var}");
+ Map<String, String> result = t.match(new UriTemplate("/a/b/"));
+
+ Assert.assertNull(result);
+ }
+
+
+ @Test
+ public void testSpecExample2_05() throws Exception {
UriTemplate t = new UriTemplate("/a/{var}");
Map<String, String> result = t.match(new UriTemplate("/a/b/c"));
@@ -153,6 +171,17 @@ public class TestUriTemplate {
}
+ @Test
+ public void testSpecExample2_06() throws Exception {
+ // Extra test based on RFC 6570, 2.3
+ UriTemplate t = new UriTemplate("/a/{var}");
+ Map<String, String> result = t.match(new UriTemplate("/a/"));
+
+ Assert.assertEquals(1, result.size());
+ Assert.assertEquals("", result.get("var"));
+ }
+
+
@Test(expected = jakarta.websocket.DeploymentException.class)
public void testDuplicate01() throws Exception {
@SuppressWarnings("unused")
@@ -170,45 +199,12 @@ public class TestUriTemplate {
Assert.assertEquals("x", result.get("b"));
}
-
- public void testEgMailingList01() throws Exception {
- UriTemplate t = new UriTemplate("/a/{var}");
- Map<String, String> result = t.match(new UriTemplate("/a/b/"));
-
- Assert.assertNull(result);
- }
-
-
- public void testEgMailingList02() throws Exception {
- UriTemplate t = new UriTemplate("/a/{var}");
- Map<String, String> result = t.match(new UriTemplate("/a/"));
-
- Assert.assertNull(result);
- }
-
-
@Test
- public void testEgMailingList03() throws Exception {
- UriTemplate t = new UriTemplate("/a/{var}");
- Map<String, String> result = t.match(new UriTemplate("/a"));
-
- Assert.assertNull(result);
- }
-
-
- @Test(expected = jakarta.websocket.DeploymentException.class)
- public void testEgMailingList04() throws Exception {
- UriTemplate t = new UriTemplate("/a/{var1}/{var2}");
- @SuppressWarnings("unused")
- Map<String, String> result = t.match(new UriTemplate("/a//c"));
- }
-
-
- @Test(expected = jakarta.websocket.DeploymentException.class)
- public void testEgMailingList05() throws Exception {
+ public void testEgMailingList01() throws Exception {
UriTemplate t = new UriTemplate("/a/{var}/");
- @SuppressWarnings("unused")
Map<String, String> result = t.match(new UriTemplate("/a/b/"));
+ Assert.assertEquals(1, result.size());
+ Assert.assertEquals("b", result.get("var"));
}
diff --git a/webapps/docs/changelog.xml b/webapps/docs/changelog.xml
index ff25e54db7..a093b00c27 100644
--- a/webapps/docs/changelog.xml
+++ b/webapps/docs/changelog.xml
@@ -221,6 +221,13 @@
<code>org.apache.tomcat.websocket.MAX_HTTP_RESPONSE_HEADER_BYTES</code>
user property. (markt)
</add>
+ <fix>
+ Improve URI template matching for WebSocket end points. Trailing
slashes
+ are now significant both for template definitions and URIs considered
+ for potential matches to those URIs. Note that this means if a URI
+ template ends in a variable without a trailing slash, that variable
+ might be expanded to the empty string. (markt)
+ </fix>
</changelog>
</subsection>
<subsection name="Other">
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]