From 024a053455f203c3d967bf757779cbd963806dff Mon Sep 17 00:00:00 2001 From: Greg Wilkins Date: Tue, 22 Mar 2022 09:48:09 +0100 Subject: [PATCH 1/7] Issue #7748 - allow override of path mapping behavior in ServletContextHandler (#7614) Added protected method to ServletHandler to allow other servlet mappings (eg regex) in embedded/extended usage Signed-off-by: Greg Wilkins Signed-off-by: Joakim Erdfelt --- .../eclipse/jetty/ee10/servlet/ServletPathMapping.java | 7 +------ .../org/eclipse/jetty/ee9/servlet/ServletHandler.java | 1 + .../eclipse/jetty/ee9/servlet/RegexServletTest.java | 10 +++++----- 3 files changed, 7 insertions(+), 11 deletions(-) diff --git a/jetty-ee10/jetty-ee10-servlet/src/main/java/org/eclipse/jetty/ee10/servlet/ServletPathMapping.java b/jetty-ee10/jetty-ee10-servlet/src/main/java/org/eclipse/jetty/ee10/servlet/ServletPathMapping.java index 79c41a18b429..2fdb0e4dc045 100644 --- a/jetty-ee10/jetty-ee10-servlet/src/main/java/org/eclipse/jetty/ee10/servlet/ServletPathMapping.java +++ b/jetty-ee10/jetty-ee10-servlet/src/main/java/org/eclipse/jetty/ee10/servlet/ServletPathMapping.java @@ -85,12 +85,6 @@ public ServletPathMapping(PathSpec pathSpec, String servletName, String pathInCo break; case MIDDLE_GLOB: - _mappingMatch = null; - _matchValue = ""; - _servletPath = pathInContext; - _pathInfo = null; - break; - default: throw new IllegalStateException(); } @@ -104,6 +98,7 @@ else if (pathSpec != null) } else { + // TODO can we do better for RegexPathSpec _mappingMatch = null; _matchValue = ""; _servletPath = pathInContext; diff --git a/jetty-ee9/jetty-ee9-servlet/src/main/java/org/eclipse/jetty/ee9/servlet/ServletHandler.java b/jetty-ee9/jetty-ee9-servlet/src/main/java/org/eclipse/jetty/ee9/servlet/ServletHandler.java index d5cd21c5e6ec..ec9fb5632174 100644 --- a/jetty-ee9/jetty-ee9-servlet/src/main/java/org/eclipse/jetty/ee9/servlet/ServletHandler.java +++ b/jetty-ee9/jetty-ee9-servlet/src/main/java/org/eclipse/jetty/ee9/servlet/ServletHandler.java @@ -1287,6 +1287,7 @@ protected void updateNameMappings() protected PathSpec asPathSpec(String pathSpec) { + // By default only allow servlet path specs return new ServletPathSpec(pathSpec); } diff --git a/jetty-ee9/jetty-ee9-servlet/src/test/java/org/eclipse/jetty/ee9/servlet/RegexServletTest.java b/jetty-ee9/jetty-ee9-servlet/src/test/java/org/eclipse/jetty/ee9/servlet/RegexServletTest.java index 985769bb1209..6522900ce039 100644 --- a/jetty-ee9/jetty-ee9-servlet/src/test/java/org/eclipse/jetty/ee9/servlet/RegexServletTest.java +++ b/jetty-ee9/jetty-ee9-servlet/src/test/java/org/eclipse/jetty/ee9/servlet/RegexServletTest.java @@ -79,7 +79,7 @@ public void testMapping() throws Exception assertThat(response, containsString("servletPath='/test/info'")); assertThat(response, containsString("pathInfo='null'")); assertThat(response, containsString("mapping.mappingMatch='null'")); - assertThat(response, containsString("mapping.matchValue='test/info'")); + assertThat(response, containsString("mapping.matchValue=''")); assertThat(response, containsString("mapping.pattern='^/test/.*$'")); } @@ -93,10 +93,10 @@ public void testForward() throws Exception String response = _connector.getResponse("GET /ctx/forward/ignore HTTP/1.0\r\n\r\n"); assertThat(response, containsString(" 200 OK")); assertThat(response, containsString("contextPath='/ctx'")); - assertThat(response, containsString("servletPath='/Test'")); - assertThat(response, containsString("pathInfo='/info'")); + assertThat(response, containsString("servletPath='/Test/info'")); + assertThat(response, containsString("pathInfo='null'")); assertThat(response, containsString("mapping.mappingMatch='null'")); - assertThat(response, containsString("mapping.matchValue='Test'")); + assertThat(response, containsString("mapping.matchValue=''")); assertThat(response, containsString("mapping.pattern='^/[Tt]est(/.*)?'")); } @@ -113,7 +113,7 @@ public void testInclude() throws Exception assertThat(response, containsString("servletPath='/include'")); assertThat(response, containsString("pathInfo='null'")); assertThat(response, containsString("mapping.mappingMatch='null'")); - assertThat(response, containsString("mapping.matchValue='include'")); + assertThat(response, containsString("mapping.matchValue=''")); assertThat(response, containsString("mapping.pattern='^/include$'")); } From 351fe53c9a4b880dcd776cfddc74d1944eb4169b Mon Sep 17 00:00:00 2001 From: Greg Wilkins Date: Mon, 25 Apr 2022 08:30:31 +0200 Subject: [PATCH 2/7] Fix #7891 regex pathInfo (#7892) Fix 7891 regex pathInfo + Use the pathSpec methods to set servletPath and pathInfo when possible Signed-off-by: Greg Wilkins --- .../jetty/ee10/servlet/ServletPathMapping.java | 1 - .../org/eclipse/jetty/ee9/nested/RequestTest.java | 11 ++++++----- .../eclipse/jetty/ee9/servlet/RegexServletTest.java | 6 +++--- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/jetty-ee10/jetty-ee10-servlet/src/main/java/org/eclipse/jetty/ee10/servlet/ServletPathMapping.java b/jetty-ee10/jetty-ee10-servlet/src/main/java/org/eclipse/jetty/ee10/servlet/ServletPathMapping.java index 2fdb0e4dc045..8eb7af4cfeb2 100644 --- a/jetty-ee10/jetty-ee10-servlet/src/main/java/org/eclipse/jetty/ee10/servlet/ServletPathMapping.java +++ b/jetty-ee10/jetty-ee10-servlet/src/main/java/org/eclipse/jetty/ee10/servlet/ServletPathMapping.java @@ -98,7 +98,6 @@ else if (pathSpec != null) } else { - // TODO can we do better for RegexPathSpec _mappingMatch = null; _matchValue = ""; _servletPath = pathInContext; diff --git a/jetty-ee9/jetty-ee9-nested/src/test/java/org/eclipse/jetty/ee9/nested/RequestTest.java b/jetty-ee9/jetty-ee9-nested/src/test/java/org/eclipse/jetty/ee9/nested/RequestTest.java index 872358254255..0ee58ab9dbd8 100644 --- a/jetty-ee9/jetty-ee9-nested/src/test/java/org/eclipse/jetty/ee9/nested/RequestTest.java +++ b/jetty-ee9/jetty-ee9-nested/src/test/java/org/eclipse/jetty/ee9/nested/RequestTest.java @@ -64,6 +64,7 @@ import org.eclipse.jetty.http.MetaData; import org.eclipse.jetty.http.MimeTypes; import org.eclipse.jetty.http.UriCompliance; +import org.eclipse.jetty.http.pathmap.RegexPathSpec; import org.eclipse.jetty.http.pathmap.MatchedPath; import org.eclipse.jetty.http.pathmap.RegexPathSpec; import org.eclipse.jetty.http.pathmap.ServletPathSpec; @@ -469,7 +470,7 @@ public void testMultiPart() throws Exception return s.count() == 2; } }; - + _server.stop(); _context.setContextPath("/foo"); _context.setResourceBase("."); @@ -1686,11 +1687,11 @@ public void testCookieLeak() throws Exception assertEquals("value", cookies[0]); assertNull(cookies[1]); } - + /** * Test that multiple requests on the same connection with different cookies * do not bleed cookies. - * + * * @throws Exception */ @Test @@ -1733,7 +1734,7 @@ public void handle(String target, Request baseRequest, HttpServletRequest reques response = HttpTester.parseResponse(lep.getResponse()); checkCookieResult(sessionId3, new String[] {sessionId1, sessionId2}, response.getContent()); } - + @Test public void testHashDOSKeys() throws Exception { @@ -2402,7 +2403,7 @@ public void clearAttributes() { } } - + private static void checkCookieResult(String containedCookie, String[] notContainedCookies, String response) { assertNotNull(containedCookie); diff --git a/jetty-ee9/jetty-ee9-servlet/src/test/java/org/eclipse/jetty/ee9/servlet/RegexServletTest.java b/jetty-ee9/jetty-ee9-servlet/src/test/java/org/eclipse/jetty/ee9/servlet/RegexServletTest.java index 6522900ce039..571f72a65c22 100644 --- a/jetty-ee9/jetty-ee9-servlet/src/test/java/org/eclipse/jetty/ee9/servlet/RegexServletTest.java +++ b/jetty-ee9/jetty-ee9-servlet/src/test/java/org/eclipse/jetty/ee9/servlet/RegexServletTest.java @@ -79,7 +79,7 @@ public void testMapping() throws Exception assertThat(response, containsString("servletPath='/test/info'")); assertThat(response, containsString("pathInfo='null'")); assertThat(response, containsString("mapping.mappingMatch='null'")); - assertThat(response, containsString("mapping.matchValue=''")); + assertThat(response, containsString("mapping.matchValue='test/info'")); assertThat(response, containsString("mapping.pattern='^/test/.*$'")); } @@ -96,7 +96,7 @@ public void testForward() throws Exception assertThat(response, containsString("servletPath='/Test/info'")); assertThat(response, containsString("pathInfo='null'")); assertThat(response, containsString("mapping.mappingMatch='null'")); - assertThat(response, containsString("mapping.matchValue=''")); + assertThat(response, containsString("mapping.matchValue='Test/info'")); assertThat(response, containsString("mapping.pattern='^/[Tt]est(/.*)?'")); } @@ -113,7 +113,7 @@ public void testInclude() throws Exception assertThat(response, containsString("servletPath='/include'")); assertThat(response, containsString("pathInfo='null'")); assertThat(response, containsString("mapping.mappingMatch='null'")); - assertThat(response, containsString("mapping.matchValue=''")); + assertThat(response, containsString("mapping.matchValue='include'")); assertThat(response, containsString("mapping.pattern='^/include$'")); } From 25dd6d0ef7ba22f96a7c39213c5b6be011f603f4 Mon Sep 17 00:00:00 2001 From: Joakim Erdfelt Date: Wed, 8 Jun 2022 12:36:30 -0500 Subject: [PATCH 3/7] Cherry-pick of Improvements to PathSpec for Jetty 10.0.x (#8136) * Cherry-pick of Improvements to PathSpec. * From commit: 5b4d1dd1c64482d00919029e0a2ba4ac1f4d8e6b * Fixing ConstraintSecurityHandler usage of PathMappings * Fixing bad INCLUDE logic from cherry-pick in ServletHandler.doScope() * Cleanup of non ServletPathSpec behaviors in ServletPathMapping class * Skip optional group name/info lookup if regex fails. * Prevent NPE on static servletPathMappings * Update WebSocketMappings to use new PathMappings.getMatched(String) Signed-off-by: Joakim Erdfelt --- .../jetty/http/pathmap/PathMappings.java | 17 ++- .../jetty/http/pathmap/RegexPathSpec.java | 119 +++++++++++++-- .../jetty/http/pathmap/RegexPathSpecTest.java | 7 +- .../test/resources/jetty-logging.properties | 1 + .../ee10/servlet/ServletPathMapping.java | 138 +++++++++++------- .../eclipse/jetty/ee9/nested/RequestTest.java | 1 + 6 files changed, 209 insertions(+), 74 deletions(-) diff --git a/jetty-core/jetty-http/src/main/java/org/eclipse/jetty/http/pathmap/PathMappings.java b/jetty-core/jetty-http/src/main/java/org/eclipse/jetty/http/pathmap/PathMappings.java index 8664fbf3896c..f094b5080dd0 100644 --- a/jetty-core/jetty-http/src/main/java/org/eclipse/jetty/http/pathmap/PathMappings.java +++ b/jetty-core/jetty-http/src/main/java/org/eclipse/jetty/http/pathmap/PathMappings.java @@ -178,13 +178,14 @@ public MatchedResource getMatched(String path) { MappedResource candidate = _exactMap.getBest(path, 0, i--); if (candidate == null) - continue; + break; matchedPath = candidate.getPathSpec().matched(path); if (matchedPath != null) { return new MatchedResource<>(candidate.getResource(), candidate.getPathSpec(), matchedPath); } + i--; } // If we reached here, there's NO optimized EXACT Match possible, skip simple match below skipRestOfGroup = true; @@ -201,11 +202,12 @@ public MatchedResource getMatched(String path) { MappedResource candidate = _prefixMap.getBest(path, 0, i--); if (candidate == null) - continue; + break; matchedPath = candidate.getPathSpec().matched(path); if (matchedPath != null) return new MatchedResource<>(candidate.getResource(), candidate.getPathSpec(), matchedPath); + i--; } // If we reached here, there's NO optimized PREFIX Match possible, skip simple match below skipRestOfGroup = true; @@ -227,7 +229,7 @@ public MatchedResource getMatched(String path) { MappedResource candidate = _suffixMap.get(path, i + 1, path.length() - i - 1); if (candidate == null) - continue; + break; matchedPath = candidate.getPathSpec().matched(path); if (matchedPath != null) @@ -259,6 +261,15 @@ public Iterator> iterator() return _mappings.iterator(); } + /** + * @deprecated use {@link PathSpec#from(String)} instead + */ + @Deprecated + public static PathSpec asPathSpec(String pathSpecString) + { + return PathSpec.from(pathSpecString); + } + public E get(PathSpec spec) { return _mappings.stream() diff --git a/jetty-core/jetty-http/src/main/java/org/eclipse/jetty/http/pathmap/RegexPathSpec.java b/jetty-core/jetty-http/src/main/java/org/eclipse/jetty/http/pathmap/RegexPathSpec.java index f58645e212c6..12a0b90a7df7 100644 --- a/jetty-core/jetty-http/src/main/java/org/eclipse/jetty/http/pathmap/RegexPathSpec.java +++ b/jetty-core/jetty-http/src/main/java/org/eclipse/jetty/http/pathmap/RegexPathSpec.java @@ -125,9 +125,8 @@ public RegexPathSpec(String regex) declaration = regex; int specLength = declaration.length(); // build up a simple signature we can use to identify the grouping - boolean inCharacterClass = false; + boolean inTextList = false; boolean inQuantifier = false; - boolean inCaptureGroup = false; StringBuilder signature = new StringBuilder(); int pathDepth = 0; @@ -140,6 +139,8 @@ public RegexPathSpec(String regex) case '^': // ignore anchors case '$': // ignore anchors case '\'': // ignore escaping + case '(': // ignore grouping + case ')': // ignore grouping break; case '+': // single char quantifier case '?': // single char quantifier @@ -148,32 +149,25 @@ public RegexPathSpec(String regex) case '.': // any char token signature.append('g'); // glob break; - case '(': // in regex capture group - inCaptureGroup = true; - break; - case ')': - inCaptureGroup = false; - signature.append('g'); - break; - case '{': // in regex quantifier + case '{': inQuantifier = true; break; case '}': inQuantifier = false; break; - case '[': // in regex character class - inCharacterClass = true; + case '[': + inTextList = true; break; case ']': - inCharacterClass = false; + inTextList = false; signature.append('g'); // glob break; case '/': - if (!inCharacterClass && !inQuantifier && !inCaptureGroup) + if (!inTextList && !inQuantifier) pathDepth++; break; default: - if (!inCharacterClass && !inQuantifier && !inCaptureGroup && Character.isLetterOrDigit(c)) + if (!inTextList && !inQuantifier && Character.isLetterOrDigit(c)) { if (last == '\\') // escaped { @@ -325,6 +319,101 @@ public MatchedPath matched(String path) return null; } + private class RegexMatchedPath implements MatchedPath + { + private final RegexPathSpec pathSpec; + private final String path; + private final Matcher matcher; + + public RegexMatchedPath(RegexPathSpec regexPathSpec, String path, Matcher matcher) + { + this.pathSpec = regexPathSpec; + this.path = path; + this.matcher = matcher; + } + + @Override + public String getPathMatch() + { + try + { + String p = matcher.group("name"); + if (p != null) + { + return p; + } + } + catch (IllegalArgumentException ignore) + { + // ignore if group name not found. + } + + if (pathSpec.getGroup() == PathSpecGroup.PREFIX_GLOB && matcher.groupCount() >= 1) + { + int idx = matcher.start(1); + if (idx > 0) + { + if (this.path.charAt(idx - 1) == '/') + idx--; + return this.path.substring(0, idx); + } + } + + // default is the full path + return this.path; + } + + @Override + public String getPathInfo() + { + try + { + String p = matcher.group("info"); + if (p != null) + { + return p; + } + } + catch (IllegalArgumentException ignore) + { + // ignore if group info not found. + } + + // Path Info only valid for PREFIX_GLOB + if (pathSpec.getGroup() == PathSpecGroup.PREFIX_GLOB && matcher.groupCount() >= 1) + { + String pathInfo = matcher.group(1); + if ("".equals(pathInfo)) + return "/"; + else + return pathInfo; + } + + // default is null + return null; + } + + @Override + public String toString() + { + return getClass().getSimpleName() + "[" + + "pathSpec=" + pathSpec + + ", path=\"" + path + "\"" + + ", matcher=" + matcher + + ']'; + } + + @Override + public MatchedPath matched(String path) + { + Matcher matcher = getMatcher(path); + if (matcher.matches()) + { + return new RegexMatchedPath(this, path, matcher); + } + return null; + } + private class RegexMatchedPath implements MatchedPath { private final RegexPathSpec pathSpec; diff --git a/jetty-core/jetty-http/src/test/java/org/eclipse/jetty/http/pathmap/RegexPathSpecTest.java b/jetty-core/jetty-http/src/test/java/org/eclipse/jetty/http/pathmap/RegexPathSpecTest.java index 474b909acd2b..878672033be5 100644 --- a/jetty-core/jetty-http/src/test/java/org/eclipse/jetty/http/pathmap/RegexPathSpecTest.java +++ b/jetty-core/jetty-http/src/test/java/org/eclipse/jetty/http/pathmap/RegexPathSpecTest.java @@ -28,6 +28,9 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; public class RegexPathSpecTest { @@ -201,8 +204,8 @@ public void testSuffixSpecTraditional() assertNotMatches(spec, "/aa/bb"); assertNotMatches(spec, "/aa/bb.do/more"); - assertThat(spec.getPathMatch("/a/b/c.do"), equalTo("")); - assertThat(spec.getPathInfo("/a/b/c.do"), equalTo("/a/b/c.do")); + assertThat(spec.getPathMatch("/a/b/c.do"), equalTo("/a/b/c.do")); + assertThat(spec.getPathInfo("/a/b/c.do"), nullValue()); } /** diff --git a/jetty-ee10/jetty-ee10-maven-plugin/src/test/resources/jetty-logging.properties b/jetty-ee10/jetty-ee10-maven-plugin/src/test/resources/jetty-logging.properties index c1e6a540a536..1ab206d22d5a 100644 --- a/jetty-ee10/jetty-ee10-maven-plugin/src/test/resources/jetty-logging.properties +++ b/jetty-ee10/jetty-ee10-maven-plugin/src/test/resources/jetty-logging.properties @@ -3,3 +3,4 @@ #org.eclipse.jetty.LEVEL=DEBUG #org.eclipse.jetty.server.LEVEL=DEBUG #org.eclipse.jetty.http.LEVEL=DEBUG +#org.eclipse.jetty.http.pathmap.LEVEL=DEBUG diff --git a/jetty-ee10/jetty-ee10-servlet/src/main/java/org/eclipse/jetty/ee10/servlet/ServletPathMapping.java b/jetty-ee10/jetty-ee10-servlet/src/main/java/org/eclipse/jetty/ee10/servlet/ServletPathMapping.java index 8eb7af4cfeb2..e918ba543845 100644 --- a/jetty-ee10/jetty-ee10-servlet/src/main/java/org/eclipse/jetty/ee10/servlet/ServletPathMapping.java +++ b/jetty-ee10/jetty-ee10-servlet/src/main/java/org/eclipse/jetty/ee10/servlet/ServletPathMapping.java @@ -16,6 +16,7 @@ import jakarta.servlet.http.HttpServletMapping; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.MappingMatch; +import org.eclipse.jetty.http.pathmap.MatchedPath; import org.eclipse.jetty.http.pathmap.PathSpec; import org.eclipse.jetty.http.pathmap.ServletPathSpec; @@ -38,71 +39,100 @@ public class ServletPathMapping implements HttpServletMapping private final String _servletPath; private final String _pathInfo; - public ServletPathMapping(PathSpec pathSpec, String servletName, String pathInContext) + public ServletPathMapping(PathSpec pathSpec, String servletName, String pathInContext, MatchedPath matchedPath) { _servletName = (servletName == null ? "" : servletName); - _pattern = pathSpec == null ? null : pathSpec.getDeclaration(); - if (pathSpec instanceof ServletPathSpec && pathInContext != null) - { - switch (pathSpec.getGroup()) - { - case ROOT: - _mappingMatch = MappingMatch.CONTEXT_ROOT; - _matchValue = ""; - _servletPath = ""; - _pathInfo = "/"; - break; - - case DEFAULT: - _mappingMatch = MappingMatch.DEFAULT; - _matchValue = ""; - _servletPath = pathInContext; - _pathInfo = null; - break; - - case EXACT: - _mappingMatch = MappingMatch.EXACT; - _matchValue = _pattern.startsWith("/") ? _pattern.substring(1) : _pattern; - _servletPath = _pattern; - _pathInfo = null; - break; - - case PREFIX_GLOB: - _mappingMatch = MappingMatch.PATH; - _servletPath = pathSpec.getPrefix(); - // TODO avoid the substring on the known servletPath! - _matchValue = _servletPath.startsWith("/") ? _servletPath.substring(1) : _servletPath; - _pathInfo = pathSpec.getPathInfo(pathInContext); - break; - - case SUFFIX_GLOB: - _mappingMatch = MappingMatch.EXTENSION; - int dot = pathInContext.lastIndexOf('.'); - _matchValue = pathInContext.substring(pathInContext.startsWith("/") ? 1 : 0, dot); - _servletPath = pathInContext; - _pathInfo = null; - break; - - case MIDDLE_GLOB: - default: - throw new IllegalStateException(); - } - } - else if (pathSpec != null) + if (pathSpec == null) { + _pattern = null; _mappingMatch = null; - _servletPath = pathSpec.getPathMatch(pathInContext); - _matchValue = _servletPath.startsWith("/") ? _servletPath.substring(1) : _servletPath; - _pathInfo = pathSpec.getPathInfo(pathInContext); + _matchValue = ""; + _servletPath = pathInContext; + _pathInfo = null; + return; } - else + + if (pathInContext == null) { + _pattern = pathSpec.getDeclaration(); _mappingMatch = null; _matchValue = ""; - _servletPath = pathInContext; + _servletPath = ""; _pathInfo = null; + return; + } + + // Path Spec types that are not ServletPathSpec + if (!(pathSpec instanceof ServletPathSpec)) + { + _pattern = pathSpec.getDeclaration(); + _mappingMatch = null; + if (matchedPath != null) + { + _servletPath = matchedPath.getPathMatch(); + _pathInfo = matchedPath.getPathInfo(); + } + else + { + _servletPath = pathInContext; + _pathInfo = null; + } + _matchValue = _servletPath.substring(_servletPath.charAt(0) == '/' ? 1 : 0); + return; } + + // from here down is ServletPathSpec behavior + _pattern = pathSpec.getDeclaration(); + + switch (pathSpec.getGroup()) + { + case ROOT: + _mappingMatch = MappingMatch.CONTEXT_ROOT; + _matchValue = ""; + _servletPath = ""; + _pathInfo = "/"; + break; + + case DEFAULT: + _mappingMatch = MappingMatch.DEFAULT; + _matchValue = ""; + _servletPath = pathInContext; + _pathInfo = null; + break; + + case EXACT: + _mappingMatch = MappingMatch.EXACT; + _matchValue = _pattern.startsWith("/") ? _pattern.substring(1) : _pattern; + _servletPath = _pattern; + _pathInfo = null; + break; + + case PREFIX_GLOB: + _mappingMatch = MappingMatch.PATH; + _servletPath = pathSpec.getPrefix(); + // TODO avoid the substring on the known servletPath! + _matchValue = _servletPath.startsWith("/") ? _servletPath.substring(1) : _servletPath; + _pathInfo = matchedPath != null ? matchedPath.getPathInfo() : null; + break; + + case SUFFIX_GLOB: + _mappingMatch = MappingMatch.EXTENSION; + int dot = pathInContext.lastIndexOf('.'); + _matchValue = pathInContext.substring(pathInContext.startsWith("/") ? 1 : 0, dot); + _servletPath = pathInContext; + _pathInfo = null; + break; + + case MIDDLE_GLOB: + default: + throw new IllegalStateException("ServletPathSpec of type MIDDLE_GLOB"); + } + } + + public ServletPathMapping(PathSpec pathSpec, String servletName, String pathInContext) + { + this(pathSpec, servletName, pathInContext, null); } @Override diff --git a/jetty-ee9/jetty-ee9-nested/src/test/java/org/eclipse/jetty/ee9/nested/RequestTest.java b/jetty-ee9/jetty-ee9-nested/src/test/java/org/eclipse/jetty/ee9/nested/RequestTest.java index 0ee58ab9dbd8..6ce12c1518f2 100644 --- a/jetty-ee9/jetty-ee9-nested/src/test/java/org/eclipse/jetty/ee9/nested/RequestTest.java +++ b/jetty-ee9/jetty-ee9-nested/src/test/java/org/eclipse/jetty/ee9/nested/RequestTest.java @@ -64,6 +64,7 @@ import org.eclipse.jetty.http.MetaData; import org.eclipse.jetty.http.MimeTypes; import org.eclipse.jetty.http.UriCompliance; +import org.eclipse.jetty.http.pathmap.MatchedPath; import org.eclipse.jetty.http.pathmap.RegexPathSpec; import org.eclipse.jetty.http.pathmap.MatchedPath; import org.eclipse.jetty.http.pathmap.RegexPathSpec; From 3dd47d1bff6d1fc1391f8fc2f2fcaf5d5e8fd1e1 Mon Sep 17 00:00:00 2001 From: Joakim Erdfelt Date: Fri, 7 Oct 2022 05:12:56 -0500 Subject: [PATCH 4/7] Cleanup post-cherry-pick of RegexPathSpec changes Signed-off-by: Joakim Erdfelt --- .../jetty/http/pathmap/PathMappings.java | 17 +-- .../jetty/http/pathmap/RegexPathSpec.java | 119 +++--------------- .../jetty/http/pathmap/RegexPathSpecTest.java | 7 +- .../eclipse/jetty/ee9/nested/RequestTest.java | 2 - 4 files changed, 20 insertions(+), 125 deletions(-) diff --git a/jetty-core/jetty-http/src/main/java/org/eclipse/jetty/http/pathmap/PathMappings.java b/jetty-core/jetty-http/src/main/java/org/eclipse/jetty/http/pathmap/PathMappings.java index f094b5080dd0..8664fbf3896c 100644 --- a/jetty-core/jetty-http/src/main/java/org/eclipse/jetty/http/pathmap/PathMappings.java +++ b/jetty-core/jetty-http/src/main/java/org/eclipse/jetty/http/pathmap/PathMappings.java @@ -178,14 +178,13 @@ public MatchedResource getMatched(String path) { MappedResource candidate = _exactMap.getBest(path, 0, i--); if (candidate == null) - break; + continue; matchedPath = candidate.getPathSpec().matched(path); if (matchedPath != null) { return new MatchedResource<>(candidate.getResource(), candidate.getPathSpec(), matchedPath); } - i--; } // If we reached here, there's NO optimized EXACT Match possible, skip simple match below skipRestOfGroup = true; @@ -202,12 +201,11 @@ public MatchedResource getMatched(String path) { MappedResource candidate = _prefixMap.getBest(path, 0, i--); if (candidate == null) - break; + continue; matchedPath = candidate.getPathSpec().matched(path); if (matchedPath != null) return new MatchedResource<>(candidate.getResource(), candidate.getPathSpec(), matchedPath); - i--; } // If we reached here, there's NO optimized PREFIX Match possible, skip simple match below skipRestOfGroup = true; @@ -229,7 +227,7 @@ public MatchedResource getMatched(String path) { MappedResource candidate = _suffixMap.get(path, i + 1, path.length() - i - 1); if (candidate == null) - break; + continue; matchedPath = candidate.getPathSpec().matched(path); if (matchedPath != null) @@ -261,15 +259,6 @@ public Iterator> iterator() return _mappings.iterator(); } - /** - * @deprecated use {@link PathSpec#from(String)} instead - */ - @Deprecated - public static PathSpec asPathSpec(String pathSpecString) - { - return PathSpec.from(pathSpecString); - } - public E get(PathSpec spec) { return _mappings.stream() diff --git a/jetty-core/jetty-http/src/main/java/org/eclipse/jetty/http/pathmap/RegexPathSpec.java b/jetty-core/jetty-http/src/main/java/org/eclipse/jetty/http/pathmap/RegexPathSpec.java index 12a0b90a7df7..f58645e212c6 100644 --- a/jetty-core/jetty-http/src/main/java/org/eclipse/jetty/http/pathmap/RegexPathSpec.java +++ b/jetty-core/jetty-http/src/main/java/org/eclipse/jetty/http/pathmap/RegexPathSpec.java @@ -125,8 +125,9 @@ public RegexPathSpec(String regex) declaration = regex; int specLength = declaration.length(); // build up a simple signature we can use to identify the grouping - boolean inTextList = false; + boolean inCharacterClass = false; boolean inQuantifier = false; + boolean inCaptureGroup = false; StringBuilder signature = new StringBuilder(); int pathDepth = 0; @@ -139,8 +140,6 @@ public RegexPathSpec(String regex) case '^': // ignore anchors case '$': // ignore anchors case '\'': // ignore escaping - case '(': // ignore grouping - case ')': // ignore grouping break; case '+': // single char quantifier case '?': // single char quantifier @@ -149,25 +148,32 @@ public RegexPathSpec(String regex) case '.': // any char token signature.append('g'); // glob break; - case '{': + case '(': // in regex capture group + inCaptureGroup = true; + break; + case ')': + inCaptureGroup = false; + signature.append('g'); + break; + case '{': // in regex quantifier inQuantifier = true; break; case '}': inQuantifier = false; break; - case '[': - inTextList = true; + case '[': // in regex character class + inCharacterClass = true; break; case ']': - inTextList = false; + inCharacterClass = false; signature.append('g'); // glob break; case '/': - if (!inTextList && !inQuantifier) + if (!inCharacterClass && !inQuantifier && !inCaptureGroup) pathDepth++; break; default: - if (!inTextList && !inQuantifier && Character.isLetterOrDigit(c)) + if (!inCharacterClass && !inQuantifier && !inCaptureGroup && Character.isLetterOrDigit(c)) { if (last == '\\') // escaped { @@ -319,101 +325,6 @@ public MatchedPath matched(String path) return null; } - private class RegexMatchedPath implements MatchedPath - { - private final RegexPathSpec pathSpec; - private final String path; - private final Matcher matcher; - - public RegexMatchedPath(RegexPathSpec regexPathSpec, String path, Matcher matcher) - { - this.pathSpec = regexPathSpec; - this.path = path; - this.matcher = matcher; - } - - @Override - public String getPathMatch() - { - try - { - String p = matcher.group("name"); - if (p != null) - { - return p; - } - } - catch (IllegalArgumentException ignore) - { - // ignore if group name not found. - } - - if (pathSpec.getGroup() == PathSpecGroup.PREFIX_GLOB && matcher.groupCount() >= 1) - { - int idx = matcher.start(1); - if (idx > 0) - { - if (this.path.charAt(idx - 1) == '/') - idx--; - return this.path.substring(0, idx); - } - } - - // default is the full path - return this.path; - } - - @Override - public String getPathInfo() - { - try - { - String p = matcher.group("info"); - if (p != null) - { - return p; - } - } - catch (IllegalArgumentException ignore) - { - // ignore if group info not found. - } - - // Path Info only valid for PREFIX_GLOB - if (pathSpec.getGroup() == PathSpecGroup.PREFIX_GLOB && matcher.groupCount() >= 1) - { - String pathInfo = matcher.group(1); - if ("".equals(pathInfo)) - return "/"; - else - return pathInfo; - } - - // default is null - return null; - } - - @Override - public String toString() - { - return getClass().getSimpleName() + "[" + - "pathSpec=" + pathSpec + - ", path=\"" + path + "\"" + - ", matcher=" + matcher + - ']'; - } - - @Override - public MatchedPath matched(String path) - { - Matcher matcher = getMatcher(path); - if (matcher.matches()) - { - return new RegexMatchedPath(this, path, matcher); - } - return null; - } - private class RegexMatchedPath implements MatchedPath { private final RegexPathSpec pathSpec; diff --git a/jetty-core/jetty-http/src/test/java/org/eclipse/jetty/http/pathmap/RegexPathSpecTest.java b/jetty-core/jetty-http/src/test/java/org/eclipse/jetty/http/pathmap/RegexPathSpecTest.java index 878672033be5..474b909acd2b 100644 --- a/jetty-core/jetty-http/src/test/java/org/eclipse/jetty/http/pathmap/RegexPathSpecTest.java +++ b/jetty-core/jetty-http/src/test/java/org/eclipse/jetty/http/pathmap/RegexPathSpecTest.java @@ -28,9 +28,6 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNull; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertNull; -import static org.junit.jupiter.api.Assertions.assertTrue; public class RegexPathSpecTest { @@ -204,8 +201,8 @@ public void testSuffixSpecTraditional() assertNotMatches(spec, "/aa/bb"); assertNotMatches(spec, "/aa/bb.do/more"); - assertThat(spec.getPathMatch("/a/b/c.do"), equalTo("/a/b/c.do")); - assertThat(spec.getPathInfo("/a/b/c.do"), nullValue()); + assertThat(spec.getPathMatch("/a/b/c.do"), equalTo("")); + assertThat(spec.getPathInfo("/a/b/c.do"), equalTo("/a/b/c.do")); } /** diff --git a/jetty-ee9/jetty-ee9-nested/src/test/java/org/eclipse/jetty/ee9/nested/RequestTest.java b/jetty-ee9/jetty-ee9-nested/src/test/java/org/eclipse/jetty/ee9/nested/RequestTest.java index 6ce12c1518f2..65edb724e164 100644 --- a/jetty-ee9/jetty-ee9-nested/src/test/java/org/eclipse/jetty/ee9/nested/RequestTest.java +++ b/jetty-ee9/jetty-ee9-nested/src/test/java/org/eclipse/jetty/ee9/nested/RequestTest.java @@ -66,8 +66,6 @@ import org.eclipse.jetty.http.UriCompliance; import org.eclipse.jetty.http.pathmap.MatchedPath; import org.eclipse.jetty.http.pathmap.RegexPathSpec; -import org.eclipse.jetty.http.pathmap.MatchedPath; -import org.eclipse.jetty.http.pathmap.RegexPathSpec; import org.eclipse.jetty.http.pathmap.ServletPathSpec; import org.eclipse.jetty.io.Content; import org.eclipse.jetty.logging.StacklessLogging; From bada439bacc1886dc15d812ee4f90979467eb8d6 Mon Sep 17 00:00:00 2001 From: Joakim Erdfelt Date: Fri, 7 Oct 2022 05:26:06 -0500 Subject: [PATCH 5/7] Missed ee9 changes --- .../org/eclipse/jetty/ee9/servlet/RegexServletTest.java | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/jetty-ee9/jetty-ee9-servlet/src/test/java/org/eclipse/jetty/ee9/servlet/RegexServletTest.java b/jetty-ee9/jetty-ee9-servlet/src/test/java/org/eclipse/jetty/ee9/servlet/RegexServletTest.java index 571f72a65c22..8802b3e89f57 100644 --- a/jetty-ee9/jetty-ee9-servlet/src/test/java/org/eclipse/jetty/ee9/servlet/RegexServletTest.java +++ b/jetty-ee9/jetty-ee9-servlet/src/test/java/org/eclipse/jetty/ee9/servlet/RegexServletTest.java @@ -20,7 +20,6 @@ import jakarta.servlet.http.HttpServlet; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; -import org.eclipse.jetty.http.pathmap.PathMappings; import org.eclipse.jetty.http.pathmap.PathSpec; import org.eclipse.jetty.server.LocalConnector; import org.eclipse.jetty.server.Server; @@ -93,10 +92,10 @@ public void testForward() throws Exception String response = _connector.getResponse("GET /ctx/forward/ignore HTTP/1.0\r\n\r\n"); assertThat(response, containsString(" 200 OK")); assertThat(response, containsString("contextPath='/ctx'")); - assertThat(response, containsString("servletPath='/Test/info'")); - assertThat(response, containsString("pathInfo='null'")); + assertThat(response, containsString("servletPath='/Test'")); + assertThat(response, containsString("pathInfo='/info'")); assertThat(response, containsString("mapping.mappingMatch='null'")); - assertThat(response, containsString("mapping.matchValue='Test/info'")); + assertThat(response, containsString("mapping.matchValue='Test'")); assertThat(response, containsString("mapping.pattern='^/[Tt]est(/.*)?'")); } From dd3e3cf6e84bd19148a0c044697b36740916ebde Mon Sep 17 00:00:00 2001 From: Joakim Erdfelt Date: Fri, 7 Oct 2022 05:36:20 -0500 Subject: [PATCH 6/7] Aligning changes between ee9 & ee10 --- .../java/org/eclipse/jetty/ee10/servlet/ServletHandler.java | 1 + .../org/eclipse/jetty/ee9/nested/ServletPathMapping.java | 6 ------ 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/jetty-ee10/jetty-ee10-servlet/src/main/java/org/eclipse/jetty/ee10/servlet/ServletHandler.java b/jetty-ee10/jetty-ee10-servlet/src/main/java/org/eclipse/jetty/ee10/servlet/ServletHandler.java index 82508563ddb5..6841c663b7a6 100644 --- a/jetty-ee10/jetty-ee10-servlet/src/main/java/org/eclipse/jetty/ee10/servlet/ServletHandler.java +++ b/jetty-ee10/jetty-ee10-servlet/src/main/java/org/eclipse/jetty/ee10/servlet/ServletHandler.java @@ -1170,6 +1170,7 @@ protected void updateNameMappings() protected PathSpec asPathSpec(String pathSpec) { + // By default only allow servlet path specs return new ServletPathSpec(pathSpec); } diff --git a/jetty-ee9/jetty-ee9-nested/src/main/java/org/eclipse/jetty/ee9/nested/ServletPathMapping.java b/jetty-ee9/jetty-ee9-nested/src/main/java/org/eclipse/jetty/ee9/nested/ServletPathMapping.java index 3af8989433bf..bbd17b121ca8 100644 --- a/jetty-ee9/jetty-ee9-nested/src/main/java/org/eclipse/jetty/ee9/nested/ServletPathMapping.java +++ b/jetty-ee9/jetty-ee9-nested/src/main/java/org/eclipse/jetty/ee9/nested/ServletPathMapping.java @@ -125,12 +125,6 @@ public ServletPathMapping(PathSpec pathSpec, String servletName, String pathInCo break; case MIDDLE_GLOB: - _mappingMatch = null; - _matchValue = ""; - _servletPath = pathInContext; - _pathInfo = null; - break; - default: throw new IllegalStateException("ServletPathSpec of type MIDDLE_GLOB"); } From 04d8c3f451fca403166061d0eb27e2ed6692cbad Mon Sep 17 00:00:00 2001 From: Joakim Erdfelt Date: Fri, 7 Oct 2022 08:26:39 -0500 Subject: [PATCH 7/7] Updates for test failures --- .../jetty/ee10/servlet/Dispatcher.java | 16 ++++--- .../ee10/servlet/ServletContextHandler.java | 10 ++++- .../ee10/servlet/ServletContextRequest.java | 15 +++++-- .../jetty/ee10/servlet/ServletHandler.java | 45 ++++++++++++++----- 4 files changed, 63 insertions(+), 23 deletions(-) diff --git a/jetty-ee10/jetty-ee10-servlet/src/main/java/org/eclipse/jetty/ee10/servlet/Dispatcher.java b/jetty-ee10/jetty-ee10-servlet/src/main/java/org/eclipse/jetty/ee10/servlet/Dispatcher.java index 21e6347258ed..a097499b7700 100644 --- a/jetty-ee10/jetty-ee10-servlet/src/main/java/org/eclipse/jetty/ee10/servlet/Dispatcher.java +++ b/jetty-ee10/jetty-ee10-servlet/src/main/java/org/eclipse/jetty/ee10/servlet/Dispatcher.java @@ -34,6 +34,7 @@ import jakarta.servlet.http.HttpServletResponseWrapper; import org.eclipse.jetty.ee10.servlet.util.ServletOutputStreamWrapper; import org.eclipse.jetty.http.HttpURI; +import org.eclipse.jetty.http.pathmap.MatchedResource; import org.eclipse.jetty.util.Fields; import org.eclipse.jetty.util.MultiMap; import org.eclipse.jetty.util.StringUtil; @@ -71,8 +72,9 @@ public Dispatcher(ServletContextHandler contextHandler, HttpURI uri, String path _named = null; _servletHandler = _contextHandler.getServletHandler(); - _mappedServlet = _servletHandler.getMappedServlet(pathInContext); - _servletPathMapping = _mappedServlet.getServletPathMapping(_pathInContext); + MatchedResource matchedServlet = _servletHandler.getMatchedServlet(pathInContext); + _mappedServlet = matchedServlet.getResource(); + _servletPathMapping = _mappedServlet.getServletPathMapping(_pathInContext, matchedServlet.getMatchedPath()); } public Dispatcher(ServletContextHandler contextHandler, String name) throws IllegalStateException @@ -334,11 +336,11 @@ public Object getAttribute(String name) switch (name) { case RequestDispatcher.INCLUDE_MAPPING: - return _mappedServlet.getServletPathMapping(_pathInContext); + return _servletPathMapping; case RequestDispatcher.INCLUDE_SERVLET_PATH: - return _mappedServlet.getServletPathMapping(_pathInContext).getServletPath(); + return _servletPathMapping.getServletPath(); case RequestDispatcher.INCLUDE_PATH_INFO: - return _mappedServlet.getServletPathMapping(_pathInContext).getPathInfo(); + return _servletPathMapping.getPathInfo(); case RequestDispatcher.INCLUDE_REQUEST_URI: return (_uri == null) ? null : _uri.getPath(); case RequestDispatcher.INCLUDE_CONTEXT_PATH: @@ -591,13 +593,13 @@ public DispatcherType getDispatcherType() @Override public String getPathInfo() { - return _mappedServlet.getServletPathMapping(_pathInContext).getPathInfo(); + return _servletPathMapping.getPathInfo(); } @Override public String getServletPath() { - return _mappedServlet.getServletPathMapping(_pathInContext).getServletPath(); + return _servletPathMapping.getServletPath(); } @Override diff --git a/jetty-ee10/jetty-ee10-servlet/src/main/java/org/eclipse/jetty/ee10/servlet/ServletContextHandler.java b/jetty-ee10/jetty-ee10-servlet/src/main/java/org/eclipse/jetty/ee10/servlet/ServletContextHandler.java index eaa0c51d297a..c84fc601fcb5 100644 --- a/jetty-ee10/jetty-ee10-servlet/src/main/java/org/eclipse/jetty/ee10/servlet/ServletContextHandler.java +++ b/jetty-ee10/jetty-ee10-servlet/src/main/java/org/eclipse/jetty/ee10/servlet/ServletContextHandler.java @@ -74,6 +74,8 @@ import org.eclipse.jetty.ee10.servlet.security.SecurityHandler; import org.eclipse.jetty.http.HttpURI; import org.eclipse.jetty.http.MimeTypes; +import org.eclipse.jetty.http.pathmap.MappedResource; +import org.eclipse.jetty.http.pathmap.MatchedResource; import org.eclipse.jetty.server.Handler; import org.eclipse.jetty.server.Request; import org.eclipse.jetty.server.Response; @@ -1185,7 +1187,10 @@ protected void doStop() throws Exception @Override protected ServletContextRequest wrap(Request request, String pathInContext) { - ServletHandler.MappedServlet mappedServlet = _servletHandler.getMappedServlet(pathInContext); + MatchedResource matchedResource = _servletHandler.getMatchedServlet(pathInContext); + if (matchedResource == null) + return null; + ServletHandler.MappedServlet mappedServlet = matchedResource.getResource(); if (mappedServlet == null) return null; @@ -1200,7 +1205,8 @@ protected ServletContextRequest wrap(Request request, String pathInContext) // request.getComponents().getCache().put("blah.blah.ServletChannel", servletChannel); TODO: Re-enable. } - ServletContextRequest servletContextRequest = new ServletContextRequest(_servletContext, servletChannel, request, pathInContext, mappedServlet); + ServletContextRequest servletContextRequest = new ServletContextRequest(_servletContext, servletChannel, request, pathInContext, + matchedResource.getResource(), matchedResource.getPathSpec(), matchedResource.getMatchedPath()); servletChannel.init(servletContextRequest); return servletContextRequest; } diff --git a/jetty-ee10/jetty-ee10-servlet/src/main/java/org/eclipse/jetty/ee10/servlet/ServletContextRequest.java b/jetty-ee10/jetty-ee10-servlet/src/main/java/org/eclipse/jetty/ee10/servlet/ServletContextRequest.java index 8cc424dc3e56..e585366e0d11 100644 --- a/jetty-ee10/jetty-ee10-servlet/src/main/java/org/eclipse/jetty/ee10/servlet/ServletContextRequest.java +++ b/jetty-ee10/jetty-ee10-servlet/src/main/java/org/eclipse/jetty/ee10/servlet/ServletContextRequest.java @@ -67,6 +67,8 @@ import org.eclipse.jetty.http.HttpURI; import org.eclipse.jetty.http.HttpVersion; import org.eclipse.jetty.http.MimeTypes; +import org.eclipse.jetty.http.pathmap.MatchedPath; +import org.eclipse.jetty.http.pathmap.PathSpec; import org.eclipse.jetty.server.ConnectionMetaData; import org.eclipse.jetty.server.FormFields; import org.eclipse.jetty.server.Request; @@ -121,6 +123,8 @@ public static ServletContextRequest getServletContextRequest(ServletRequest requ private final HttpInput _httpInput; private final String _pathInContext; private final ServletChannel _servletChannel; + private final PathSpec _pathSpec; + final MatchedPath _matchedPath; private ServletContextResponse _response; private Charset _queryEncoding; private HttpFields _trailers; @@ -130,7 +134,9 @@ protected ServletContextRequest( ServletChannel servletChannel, Request request, String pathInContext, - ServletHandler.MappedServlet mappedServlet) + ServletHandler.MappedServlet mappedServlet, + PathSpec pathSpec, + MatchedPath matchedPath) { super(servletContextApi.getContextHandler(), servletContextApi.getContext(), request, pathInContext); _servletChannel = servletChannel; @@ -138,6 +144,8 @@ protected ServletContextRequest( _mappedServlet = mappedServlet; _httpInput = new HttpInput(_servletChannel); // TODO recycle _pathInContext = pathInContext; + _pathSpec = pathSpec; + _matchedPath = matchedPath; } @Override @@ -344,6 +352,7 @@ public class ServletApiRequest implements HttpServletRequest private Authentication _authentication; private String _method; private ServletMultiPartFormData.Parts _parts; + private ServletPathMapping _servletPathMapping; public static Session getSession(HttpSession httpSession) { @@ -535,7 +544,7 @@ public int getIntHeader(String name) @Override public String getPathInfo() { - return ServletContextRequest.this._mappedServlet.getServletPathMapping(getRequest().getPathInContext()).getPathInfo(); + return ServletContextRequest.this._matchedPath.getPathInfo(); } @Override @@ -623,7 +632,7 @@ public StringBuffer getRequestURL() @Override public String getServletPath() { - return ServletContextRequest.this._mappedServlet.getServletPathMapping(_pathInContext).getServletPath(); + return ServletContextRequest.this._matchedPath.getPathMatch(); } @Override diff --git a/jetty-ee10/jetty-ee10-servlet/src/main/java/org/eclipse/jetty/ee10/servlet/ServletHandler.java b/jetty-ee10/jetty-ee10-servlet/src/main/java/org/eclipse/jetty/ee10/servlet/ServletHandler.java index 6841c663b7a6..e8f8933272ba 100644 --- a/jetty-ee10/jetty-ee10-servlet/src/main/java/org/eclipse/jetty/ee10/servlet/ServletHandler.java +++ b/jetty-ee10/jetty-ee10-servlet/src/main/java/org/eclipse/jetty/ee10/servlet/ServletHandler.java @@ -45,6 +45,8 @@ import jakarta.servlet.http.HttpServletResponse; import org.eclipse.jetty.ee10.servlet.security.IdentityService; import org.eclipse.jetty.ee10.servlet.security.SecurityHandler; +import org.eclipse.jetty.http.pathmap.MappedResource; +import org.eclipse.jetty.http.pathmap.MatchedPath; import org.eclipse.jetty.http.pathmap.MatchedResource; import org.eclipse.jetty.http.pathmap.PathMappings; import org.eclipse.jetty.http.pathmap.PathSpec; @@ -441,25 +443,37 @@ public Request.Processor handle(Request request) throws Exception } /** - * Get MappedServlet for target. + * ServletHolder matching target path. * * @param target Path within _context or servlet name - * @return MappedServlet matched by path or name. Named servlets have a null PathSpec + * @return MatchedResource, pointing to the {@link MappedResource} for the {@link ServletHolder}, and also the pathspec specific name/info sections for the match. + * Named servlets have a null PathSpec and {@link MatchedResource}. */ - public MappedServlet getMappedServlet(String target) + public MatchedResource getMatchedServlet(String target) { if (target.startsWith("/")) { if (_servletPathMap == null) return null; - - MatchedResource match = _servletPathMap.getMatched(target); - if (match == null) - return null; - return match.getResource(); + return _servletPathMap.getMatched(target); } - return _servletNameMap.get(target); + MappedServlet holder = _servletNameMap.get(target); + if (holder == null) + return null; + return new MatchedResource<>(holder, null, MatchedPath.EMPTY); + } + + /** + * ServletHolder matching path. + * + * @param target Path within _context or servlet name + * @return MappedResource to the ServletHolder. Named servlets have a null PathSpec + */ + public MappedServlet getMappedServlet(String target) + { + MatchedResource matchedResource = getMatchedServlet(target); + return matchedResource.getResource(); } protected FilterChain getFilterChain(HttpServletRequest request, String pathInContext, ServletHolder servletHolder) @@ -1448,7 +1462,7 @@ public static class MappedServlet switch (pathSpec.getGroup()) { case EXACT: - _servletPathMapping = new ServletPathMapping(_pathSpec, _servletHolder.getName(), _pathSpec.getPrefix()); + _servletPathMapping = new ServletPathMapping(_pathSpec, _servletHolder.getName(), _pathSpec.getDeclaration()); break; case ROOT: _servletPathMapping = new ServletPathMapping(_pathSpec, _servletHolder.getName(), "/"); @@ -1479,7 +1493,16 @@ public ServletPathMapping getServletPathMapping(String pathInContext) if (_servletPathMapping != null) return _servletPathMapping; if (_pathSpec != null) - return new ServletPathMapping(_pathSpec, _servletHolder.getName(), pathInContext); + return new ServletPathMapping(_pathSpec, _servletHolder.getName(), pathInContext, null); + return null; + } + + public ServletPathMapping getServletPathMapping(String pathInContext, MatchedPath matchedPath) + { + if (_servletPathMapping != null) + return _servletPathMapping; + if (_pathSpec != null) + return new ServletPathMapping(_pathSpec, _servletHolder.getName(), pathInContext, matchedPath); return null; }