Fix HttpListener path parsing for trailing % (#90028)
authorMiha Zupan <mihazupan.zupan1@gmail.com>
Fri, 4 Aug 2023 21:52:04 +0000 (23:52 +0200)
committerGitHub <noreply@github.com>
Fri, 4 Aug 2023 21:52:04 +0000 (14:52 -0700)
src/libraries/System.Net.HttpListener/src/System/Net/HttpListenerRequestUriBuilder.cs
src/libraries/System.Net.HttpListener/tests/InvalidClientRequestTests.cs

index 3f84bed..bd0f464 100644 (file)
@@ -179,15 +179,21 @@ namespace System.Net
                 current = _rawPath[index];
                 if (current == '%')
                 {
-                    // Assert is enough, since http.sys accepted the request string already. This should never happen.
-                    Debug.Assert(index + 2 < _rawPath.Length, "Expected >=2 characters after '%' (e.g. %2F)");
+                    if (index + 2 >= _rawPath.Length)
+                    {
+                        // Not enough data for a percent encoded byte.
+                        return ParsingResult.InvalidString;
+                    }
 
                     index++;
                     current = _rawPath[index];
                     if (current == 'u' || current == 'U')
                     {
-                        // We found "%u" which means, we have a Unicode code point of the form "%uXXXX".
-                        Debug.Assert(index + 4 < _rawPath.Length, "Expected >=4 characters after '%u' (e.g. %u0062)");
+                        if (index + 4 >= _rawPath.Length)
+                        {
+                            // Not enough data for "%uXXXX".
+                            return ParsingResult.InvalidString;
+                        }
 
                         // Decode the content of rawOctets into percent encoded UTF-8 characters and append them
                         // to requestUriString.
index 3ee33e1..739c5b2 100644 (file)
@@ -97,6 +97,14 @@ namespace System.Net.Tests
 
             // ? prior to path and query.  This may or may not fail, depending on the OS, but in either case it shouldn't crash.
             yield return new object[] { "GET http://ab?cd{path} HTTP/1.1", null, null, null, "" };
+
+            // Path ending with an incomplete percent encoded byte or "%uXXXX"
+            yield return new object[] { "GET /foo/% HTTP/1.1", null, null, null, "" };
+            yield return new object[] { "GET /foo/%2 HTTP/1.1", null, null, null, "" };
+            yield return new object[] { "GET /foo/%u HTTP/1.1", null, null, null, "" };
+            yield return new object[] { "GET /foo/%uF HTTP/1.1", null, null, null, "" };
+            yield return new object[] { "GET /foo/%uFF HTTP/1.1", null, null, null, "" };
+            yield return new object[] { "GET /foo/%uFFF HTTP/1.1", null, null, null, "" };
         }
 
         [ActiveIssue("https://github.com/dotnet/runtime/issues/2284", TestRuntimes.Mono)]