This is an automated email from the ASF dual-hosted git repository.
markt-asf pushed a commit to branch 11.0.x
in repository https://gitbox.apache.org/repos/asf/tomcat.git
The following commit(s) were added to refs/heads/11.0.x by this push:
new 0f4b4764fd Refactor request.getContextPath()
0f4b4764fd is described below
commit 0f4b4764fd16176de6998dc3430102ca404bcf9c
Author: Mark Thomas <[email protected]>
AuthorDate: Tue Nov 3 14:23:20 2026 +0000
Refactor request.getContextPath()
---
.../catalina/connector/LocalStrings.properties | 1 -
java/org/apache/catalina/connector/Request.java | 113 +------------------
.../apache/catalina/util/LocalStrings.properties | 2 +
java/org/apache/catalina/util/RequestUtil.java | 125 +++++++++++++++++++++
4 files changed, 128 insertions(+), 113 deletions(-)
diff --git a/java/org/apache/catalina/connector/LocalStrings.properties
b/java/org/apache/catalina/connector/LocalStrings.properties
index 4903170310..8ab48f9d56 100644
--- a/java/org/apache/catalina/connector/LocalStrings.properties
+++ b/java/org/apache/catalina/connector/LocalStrings.properties
@@ -56,7 +56,6 @@ coyoteRequest.changeSessionId=Cannot change session ID. There
is no session asso
coyoteRequest.chunkedPostTooLarge=Parameters were not parsed because the size
of the posted data was too big. Because this request was a chunked request, it
could not be processed further. Use the maxPostSize attribute of the connector
to resolve this if the application should accept large POSTs.
coyoteRequest.deletePartFailed=Failed to delete temporary file used for part
[{0}]
coyoteRequest.filterAsyncSupportUnknown=Unable to determine if any filters do
not support async processing
-coyoteRequest.getContextPath.ise=Unable to find match between the canonical
context path [{0}] and the URI presented by the user agent [{1}]
coyoteRequest.getInputStream.ise=getReader() has already been called for this
request
coyoteRequest.getReader.ise=getInputStream() has already been called for this
request
coyoteRequest.gssLifetimeFail=Failed to obtain remaining lifetime for user
principal [{0}]
diff --git a/java/org/apache/catalina/connector/Request.java
b/java/org/apache/catalina/connector/Request.java
index 1c6631dbd7..f48f8798b1 100644
--- a/java/org/apache/catalina/connector/Request.java
+++ b/java/org/apache/catalina/connector/Request.java
@@ -97,10 +97,8 @@ import org.apache.tomcat.util.ExceptionUtils;
import org.apache.tomcat.util.buf.B2CConverter;
import org.apache.tomcat.util.buf.ByteChunk;
import org.apache.tomcat.util.buf.CharsetHolder;
-import org.apache.tomcat.util.buf.EncodedSolidusHandling;
import org.apache.tomcat.util.buf.MessageBytes;
import org.apache.tomcat.util.buf.StringUtils;
-import org.apache.tomcat.util.buf.UDecoder;
import org.apache.tomcat.util.http.CookieProcessor;
import org.apache.tomcat.util.http.FastHttpDateFormat;
import org.apache.tomcat.util.http.InvalidParameterException;
@@ -1997,116 +1995,7 @@ public class Request implements HttpServletRequest {
@Override
public String getContextPath() {
- int lastSlash = mappingData.contextSlashCount;
- // Special case handling for the root context
- if (lastSlash == 0) {
- return "";
- }
-
- String canonicalContextPath = getServletContext().getContextPath();
-
- String uri = getRequestURI();
- int pos = 0;
- if (!getContext().getAllowMultipleLeadingForwardSlashInPath()) {
- // Ensure that the returned value only starts with a single '/'.
- // This prevents the value being misinterpreted as a
protocol-relative
- // URI if used with sendRedirect().
- do {
- pos++;
- } while (pos < uri.length() && uri.charAt(pos) == '/');
- pos--;
- uri = uri.substring(pos);
- }
-
- char[] uriChars = uri.toCharArray();
- // Need at least the number of slashes in the context path
- while (lastSlash > 0) {
- pos = nextSlash(uriChars, pos + 1);
- if (pos == -1) {
- break;
- }
- lastSlash--;
- }
- // Now allow for path parameters, normalization and/or encoding.
- // Essentially, keep extending the candidate path up to the next slash
- // until the decoded and normalized candidate path (with the path
- // parameters removed) is the same as the canonical path.
- String candidate;
- if (pos == -1) {
- candidate = uri;
- } else {
- candidate = uri.substring(0, pos);
- }
- candidate = removePathParameters(candidate);
- candidate = UDecoder.URLDecode(candidate, connector.getURICharset());
- candidate =
org.apache.tomcat.util.http.RequestUtil.normalize(candidate);
- boolean match = canonicalContextPath.equals(candidate);
- while (!match && pos != -1) {
- pos = nextSlash(uriChars, pos + 1);
- if (pos == -1) {
- candidate = uri;
- } else {
- candidate = uri.substring(0, pos);
- }
- candidate = removePathParameters(candidate);
- candidate = UDecoder.URLDecode(candidate,
connector.getURICharset());
- candidate =
org.apache.tomcat.util.http.RequestUtil.normalize(candidate);
- match = canonicalContextPath.equals(candidate);
- }
- if (match) {
- if (pos == -1) {
- return uri;
- } else {
- return uri.substring(0, pos);
- }
- } else {
- // Should never happen
- throw new IllegalStateException(
- sm.getString("coyoteRequest.getContextPath.ise",
canonicalContextPath, uri));
- }
- }
-
-
- private String removePathParameters(String input) {
- int nextSemiColon = input.indexOf(';');
- // Shortcut
- if (nextSemiColon == -1) {
- return input;
- }
- StringBuilder result = new StringBuilder(input.length());
- result.append(input, 0, nextSemiColon);
- while (true) {
- int nextSlash = input.indexOf('/', nextSemiColon);
- if (nextSlash == -1) {
- break;
- }
- nextSemiColon = input.indexOf(';', nextSlash);
- if (nextSemiColon == -1) {
- result.append(input.substring(nextSlash));
- break;
- } else {
- result.append(input, nextSlash, nextSemiColon);
- }
- }
-
- return result.toString();
- }
-
-
- private int nextSlash(char[] uri, int startPos) {
- int len = uri.length;
- int pos = startPos;
- while (pos < len) {
- if (uri[pos] == '/') {
- return pos;
- } else if (connector.getEncodedSolidusHandlingInternal() ==
EncodedSolidusHandling.DECODE &&
- uri[pos] == '%' && pos + 2 < len && uri[pos + 1] == '2' &&
- (uri[pos + 2] == 'f' || uri[pos + 2] == 'F')) {
- return pos;
- }
- pos++;
- }
- return -1;
+ return RequestUtil.getContextPathUndecoded(this);
}
diff --git a/java/org/apache/catalina/util/LocalStrings.properties
b/java/org/apache/catalina/util/LocalStrings.properties
index b75bcf548d..4e43a0e2d2 100644
--- a/java/org/apache/catalina/util/LocalStrings.properties
+++ b/java/org/apache/catalina/util/LocalStrings.properties
@@ -46,6 +46,8 @@ netmaskSet.invalidNetMask=One or more netmasks provided are
invalid: {0}
parameterMap.locked=No modifications are allowed to a locked ParameterMap
+requestUtil.getContextPath.ise=Unable to find match between the canonical
context path [{0}] and the URI presented by the user agent [{1}]
+
resourceSet.locked=No modifications are allowed to a locked ResourceSet
sessionIdGeneratorBase.createRandom=Creation of SecureRandom instance for
session ID generation using [{0}] took [{1}] milliseconds.
diff --git a/java/org/apache/catalina/util/RequestUtil.java
b/java/org/apache/catalina/util/RequestUtil.java
index 5a46a95786..332e93afce 100644
--- a/java/org/apache/catalina/util/RequestUtil.java
+++ b/java/org/apache/catalina/util/RequestUtil.java
@@ -22,13 +22,20 @@ import java.util.Enumeration;
import jakarta.servlet.http.HttpServletRequest;
+import org.apache.catalina.Context;
+import org.apache.catalina.connector.Connector;
import org.apache.catalina.connector.Request;
+import org.apache.tomcat.util.buf.EncodedSolidusHandling;
import org.apache.tomcat.util.buf.UDecoder;
+import org.apache.tomcat.util.res.StringManager;
/**
* General purpose request parsing and encoding utility methods.
*/
public final class RequestUtil {
+
+ private static final StringManager sm =
StringManager.getManager(RequestUtil.class);
+
/**
* Default constructor.
*/
@@ -199,4 +206,122 @@ public final class RequestUtil {
}
return result.toString();
}
+
+
+ public static String getContextPathUndecoded(Request request) {
+
+ int lastSlash = request.getMappingData().contextSlashCount;
+ // Special case handling for the root context
+ if (lastSlash == 0) {
+ return "";
+ }
+
+ String uri = request.getRequestURI();
+ Context context = request.getContext();
+ String canonicalContextPath =
request.getServletContext().getContextPath();
+ Connector connector = request.getConnector();
+ EncodedSolidusHandling encodedSolidusHandling =
connector.getEncodedSolidusHandlingInternal();
+
+ int pos = 0;
+ if (!context.getAllowMultipleLeadingForwardSlashInPath()) {
+ // Ensure that the returned value only starts with a single '/'.
+ // This prevents the value being misinterpreted as a
protocol-relative
+ // URI if used with sendRedirect().
+ do {
+ pos++;
+ } while (pos < uri.length() && uri.charAt(pos) == '/');
+ pos--;
+ uri = uri.substring(pos);
+ }
+
+ char[] uriChars = uri.toCharArray();
+ // Need at least the number of slashes in the context path
+ while (lastSlash > 0) {
+ pos = nextSlash(uriChars, pos + 1, encodedSolidusHandling);
+ if (pos == -1) {
+ break;
+ }
+ lastSlash--;
+ }
+ // Now allow for path parameters, normalization and/or encoding.
+ // Essentially, keep extending the candidate path up to the next slash
+ // until the decoded and normalized candidate path (with the path
+ // parameters removed) is the same as the canonical path.
+ String candidate;
+ if (pos == -1) {
+ candidate = uri;
+ } else {
+ candidate = uri.substring(0, pos);
+ }
+ candidate = removePathParameters(candidate);
+ candidate = UDecoder.URLDecode(candidate, connector.getURICharset());
+ candidate =
org.apache.tomcat.util.http.RequestUtil.normalize(candidate);
+ boolean match = canonicalContextPath.equals(candidate);
+ while (!match && pos != -1) {
+ pos = nextSlash(uriChars, pos + 1, encodedSolidusHandling);
+ if (pos == -1) {
+ candidate = uri;
+ } else {
+ candidate = uri.substring(0, pos);
+ }
+ candidate = removePathParameters(candidate);
+ candidate = UDecoder.URLDecode(candidate,
connector.getURICharset());
+ candidate =
org.apache.tomcat.util.http.RequestUtil.normalize(candidate);
+ match = canonicalContextPath.equals(candidate);
+ }
+ if (match) {
+ if (pos == -1) {
+ return uri;
+ } else {
+ return uri.substring(0, pos);
+ }
+ } else {
+ // Should never happen
+ throw new IllegalStateException(
+ sm.getString("requestUtil.getContextPath.ise",
canonicalContextPath, uri));
+ }
+ }
+
+
+ private static String removePathParameters(String input) {
+ int nextSemiColon = input.indexOf(';');
+ // Shortcut
+ if (nextSemiColon == -1) {
+ return input;
+ }
+ StringBuilder result = new StringBuilder(input.length());
+ result.append(input, 0, nextSemiColon);
+ while (true) {
+ int nextSlash = input.indexOf('/', nextSemiColon);
+ if (nextSlash == -1) {
+ break;
+ }
+ nextSemiColon = input.indexOf(';', nextSlash);
+ if (nextSemiColon == -1) {
+ result.append(input.substring(nextSlash));
+ break;
+ } else {
+ result.append(input, nextSlash, nextSemiColon);
+ }
+ }
+
+ return result.toString();
+ }
+
+
+ private static int nextSlash(char[] uri, int startPos,
EncodedSolidusHandling encodedSolidusHandling) {
+ int len = uri.length;
+ int pos = startPos;
+ while (pos < len) {
+ if (uri[pos] == '/') {
+ return pos;
+ } else if (encodedSolidusHandling == EncodedSolidusHandling.DECODE
&&
+ uri[pos] == '%' && pos + 2 < len && uri[pos + 1] == '2' &&
+ (uri[pos + 2] == 'f' || uri[pos + 2] == 'F')) {
+ return pos;
+ }
+ pos++;
+ }
+ return -1;
+ }
}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]