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]

Reply via email to