This is an automated email from the ASF dual-hosted git repository.

rmaucher pushed a commit to branch 10.1.x
in repository https://gitbox.apache.org/repos/asf/tomcat.git

commit 6e4427a0b515d516d4421734938b870291815502
Author: opencode <[email protected]>
AuthorDate: Wed Oct 14 21:28:28 2026 +0200

    Treat an empty port when parsing a host value as an absent port
    
    RFC 3986 (section 3.2.3) allows a ':' separator that is not followed
    by any digits. HttpParser.validatePort() already accepted such a value
    but AbstractProcessor parsed zero digits for the port, associating a
    port of zero with the request.
    
    AbstractProcessor now treats an empty port as equivalent to an absent
    port, keeping the port already associated with the request rather than
    overwriting it with zero.
    
    Document the empty port behaviour of validatePort() for its callers and
    add tests for host values with an empty port.
---
 java/org/apache/coyote/AbstractProcessor.java      | 36 +++++++++++++---------
 .../apache/tomcat/util/http/parser/HttpParser.java |  4 +++
 .../util/http/parser/TestHttpParserHost.java       |  9 ++++++
 3 files changed, 34 insertions(+), 15 deletions(-)

diff --git a/java/org/apache/coyote/AbstractProcessor.java 
b/java/org/apache/coyote/AbstractProcessor.java
index f6be6a863b..cfa2f8c16f 100644
--- a/java/org/apache/coyote/AbstractProcessor.java
+++ b/java/org/apache/coyote/AbstractProcessor.java
@@ -354,23 +354,29 @@ public abstract class AbstractProcessor extends 
AbstractProcessorLight implement
 
             // Extract the port information first, if any
             if (colonPos != -1) {
-                int port = 0;
-                for (int i = colonPos + 1; i < valueL; i++) {
-                    char c = (char) valueB[i + valueS];
-                    if (c < '0' || c > '9') {
-                        response.setStatus(400);
-                        setErrorState(ErrorState.CLOSE_CLEAN, null);
-                        return;
+                // A ':' not followed by digits is an empty port, which the
+                // grammar allows (RFC 3986, section 3.2.3). Treat it like an
+                // absent port: keep the port already associated with the
+                // request rather than storing zero for the absent digits.
+                if (colonPos + 1 < valueL) {
+                    int port = 0;
+                    for (int i = colonPos + 1; i < valueL; i++) {
+                        char c = (char) valueB[i + valueS];
+                        if (c < '0' || c > '9') {
+                            response.setStatus(400);
+                            setErrorState(ErrorState.CLOSE_CLEAN, null);
+                            return;
+                        }
+                        int digit = c - '0';
+                        if (port > (Integer.MAX_VALUE - digit) / 10) {
+                            response.setStatus(400);
+                            setErrorState(ErrorState.CLOSE_CLEAN, null);
+                            return;
+                        }
+                        port = port * 10 + digit;
                     }
-                    int digit = c - '0';
-                    if (port > (Integer.MAX_VALUE - digit) / 10) {
-                        response.setStatus(400);
-                        setErrorState(ErrorState.CLOSE_CLEAN, null);
-                        return;
-                    }
-                    port = port * 10 + digit;
+                    request.setServerPort(port);
                 }
-                request.setServerPort(port);
 
                 // Only need to copy the host name up to the :
                 valueL = colonPos;
diff --git a/java/org/apache/tomcat/util/http/parser/HttpParser.java 
b/java/org/apache/tomcat/util/http/parser/HttpParser.java
index 505ca7d789..ed5f3ab9e1 100644
--- a/java/org/apache/tomcat/util/http/parser/HttpParser.java
+++ b/java/org/apache/tomcat/util/http/parser/HttpParser.java
@@ -1107,6 +1107,10 @@ public class HttpParser {
 
     static int validatePort(Reader reader, int colonPosition) throws 
IOException {
         // Remaining characters should be numeric ...
+        // An empty port (a ':' not followed by any digits) is permitted by the
+        // grammar (RFC 3986, section 3.2.3). It is treated as equivalent to no
+        // port being present: the colon position is returned and the caller
+        // must not overwrite the port already associated with the request.
         readInteger(reader);
         // ... followed by EOS
         if (reader.read() == -1) {
diff --git a/test/org/apache/tomcat/util/http/parser/TestHttpParserHost.java 
b/test/org/apache/tomcat/util/http/parser/TestHttpParserHost.java
index fa6e0634a8..04c058a76d 100644
--- a/test/org/apache/tomcat/util/http/parser/TestHttpParserHost.java
+++ b/test/org/apache/tomcat/util/http/parser/TestHttpParserHost.java
@@ -228,6 +228,15 @@ public class TestHttpParserHost {
         // IPv6 - invalid port
         result.add(new Object[] { TestType.IPv4, "[::1]:x", 
Integer.valueOf(-1), IAE} );
         result.add(new Object[] { TestType.IPv4, "[::1]:-1", 
Integer.valueOf(-1), IAE} );
+        // Domain name - empty port (permitted, treated as no port)
+        result.add(new Object[] { TestType.IPv4, "localhost:", 
Integer.valueOf(9), null} );
+        result.add(new Object[] { TestType.IPv4, "foo.bar.:", 
Integer.valueOf(8), null} );
+        // IPv4 - empty port (permitted, treated as no port)
+        result.add(new Object[] { TestType.IPv4, "127.0.0.1:", 
Integer.valueOf(9), null} );
+        // IPv6 - empty port (permitted, treated as no port). Only the IPv6
+        // test type is valid here: readHostIPv4() rejects the brackets before
+        // the empty port is reached.
+        result.add(new Object[] { TestType.IPv6, "[::1]:", Integer.valueOf(5), 
null} );
         return result;
     }
 


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to