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

zwoop pushed a commit to branch 9.0.x
in repository https://gitbox.apache.org/repos/asf/trafficserver.git


The following commit(s) were added to refs/heads/9.0.x by this push:
     new f2d2e92  Allow initial // in request targets. (#7266)
f2d2e92 is described below

commit f2d2e92f8afd8f61eb59737f84dc78ba4e32fb27
Author: Brian Neradt <brian.ner...@gmail.com>
AuthorDate: Mon Oct 12 12:25:03 2020 -0500

    Allow initial // in request targets. (#7266)
    
    Allow URI's with an initial double slash, such as:
    
    //index.html
    
    Co-authored-by: bneradt <bner...@verizonmedia.com>
    (cherry picked from commit aa16a29e523198728dc4dfe3b00140d4e2e913bc)
---
 proxy/hdrs/URL.cc                    |  8 +---
 proxy/hdrs/unit_tests/test_URL.cc    | 27 ++++++++---
 tests/gold_tests/url/uri.replay.yaml | 86 ++++++++++++++++++++++++++++++++++++
 tests/gold_tests/url/uri.test.py     | 37 ++++++++++++++++
 4 files changed, 146 insertions(+), 12 deletions(-)

diff --git a/proxy/hdrs/URL.cc b/proxy/hdrs/URL.cc
index c2a903b..4f7b4e8 100644
--- a/proxy/hdrs/URL.cc
+++ b/proxy/hdrs/URL.cc
@@ -1384,13 +1384,7 @@ url_parse_http(HdrHeap *heap, URLImpl *url, const char 
**start, const char *end,
     return err;
   }
 
-  cur = *start;
-  if (url->m_ptr_host == nullptr && ((end - cur) >= 2) && '/' == *cur && '/' 
== *(cur + 1)) {
-    // RFC 3986 section-3.3:
-    // If a URI does not contain an authority component, then the path cannot
-    // begin with two slash characters ("//").
-    return PARSE_RESULT_ERROR;
-  }
+  cur                     = *start;
   bool nothing_after_host = false;
   if (*start == end) {
     nothing_after_host = true;
diff --git a/proxy/hdrs/unit_tests/test_URL.cc 
b/proxy/hdrs/unit_tests/test_URL.cc
index 975bd5e..2fef10a 100644
--- a/proxy/hdrs/unit_tests/test_URL.cc
+++ b/proxy/hdrs/unit_tests/test_URL.cc
@@ -64,7 +64,8 @@ TEST_CASE("ParseRulesStrictURI", "[proxy][parseuri]")
   const struct {
     const char *const uri;
     bool valid;
-  } http_strict_uri_parsing_test_case[] = {{"/home", true},
+  } http_strict_uri_parsing_test_case[] = {{"//index.html", true},
+                                           {"/home", true},
                                            {"/path/data?key=value#id", true},
                                            {"/ABCDEFGHIJKLMNOPQRSTUVWXYZ", 
true},
                                            {"/abcdefghijklmnopqrstuvwxyz", 
true},
@@ -109,6 +110,22 @@ constexpr bool VERIFY_HOST_CHARACTERS = true;
 // clang-format off
 std::vector<url_parse_test_case> url_parse_test_cases = {
   {
+    "/index.html",
+    "/index.html",
+    VERIFY_HOST_CHARACTERS,
+    "/index.html",
+    IS_VALID,
+    IS_VALID
+  },
+  {
+    "//index.html",
+    "//index.html",
+    VERIFY_HOST_CHARACTERS,
+    "//index.html",
+    IS_VALID,
+    IS_VALID
+  },
+  {
     // The following scheme-only URI is technically valid per the spec, but we
     // have historically returned this as invalid and I'm not comfortable
     // changing it in case something depends upon this behavior. Besides, a
@@ -131,13 +148,13 @@ std::vector<url_parse_test_case> url_parse_test_cases = {
   },
   {
     // RFC 3986 section-3: When authority is not present, the path cannot begin
-    // with two slash characters ("//"). The parse_regex, though, is more
-    // forgiving.
+    // with two slash characters ("//"). We have historically allowed this,
+    // however, and will continue to do so.
+    "https:////";,
     "https:////";,
-    "",
     VERIFY_HOST_CHARACTERS,
     "https:////";,
-    !IS_VALID,
+    IS_VALID,
     IS_VALID
   },
   {
diff --git a/tests/gold_tests/url/uri.replay.yaml 
b/tests/gold_tests/url/uri.replay.yaml
new file mode 100644
index 0000000..4935ff7
--- /dev/null
+++ b/tests/gold_tests/url/uri.replay.yaml
@@ -0,0 +1,86 @@
+#  Licensed to the Apache Software Foundation (ASF) under one
+#  or more contributor license agreements.  See the NOTICE file
+#  distributed with this work for additional information
+#  regarding copyright ownership.  The ASF licenses this file
+#  to you under the Apache License, Version 2.0 (the
+#  "License"); you may not use this file except in compliance
+#  with the License.  You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing, software
+#  distributed under the License is distributed on an "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  See the License for the specific language governing permissions and
+#  limitations under the License.
+
+#
+# This replay file assumes that caching is enabled and
+# proxy.config.http.cache.ignore_client_cc_max_age is set to 0 so that we can
+# test max-age in the client requests.
+#
+
+meta:
+  version: "1.0"
+
+  blocks:
+  - 200_ok_response: &200_ok_response
+      server-response:
+        status: 200
+        reason: OK
+        headers:
+          fields:
+          - [ Content-Length, 16 ]
+          - [ Cache-Control, max-age=300 ]
+
+sessions:
+- transactions:
+
+  # A simply path
+  - all: { headers: { fields: [[ uuid, 1 ]]}}
+    client-request:
+      method: "GET"
+      version: "1.1"
+      scheme: "http"
+      url: /index.html
+      headers:
+        fields:
+        - [ Host, example.com ]
+
+    <<: *200_ok_response
+
+    proxy-response:
+      status: 200
+
+  # An initial // without an authority is not valid per RFC 3986 section-3.3,
+  # but we have historically accepted it and will continue to do so.
+  - all: { headers: { fields: [[ uuid, 2 ]]}}
+    client-request:
+      method: "GET"
+      version: "1.1"
+      scheme: "http"
+      url: //index.html
+      headers:
+        fields:
+        - [ Host, example.com ]
+
+    <<: *200_ok_response
+
+    proxy-response:
+      status: 200
+
+  # A '^' is an invalid path.
+  - all: { headers: { fields: [[ uuid, 3 ]]}}
+    client-request:
+      method: "GET"
+      version: "1.1"
+      scheme: "http"
+      url: ^
+      headers:
+        fields:
+        - [ Host, example.com ]
+
+    <<: *200_ok_response
+
+    proxy-response:
+      status: 400
diff --git a/tests/gold_tests/url/uri.test.py b/tests/gold_tests/url/uri.test.py
new file mode 100644
index 0000000..8589d07
--- /dev/null
+++ b/tests/gold_tests/url/uri.test.py
@@ -0,0 +1,37 @@
+'''
+Verify correct URI parsing behavior.
+'''
+#  Licensed to the Apache Software Foundation (ASF) under one
+#  or more contributor license agreements.  See the NOTICE file
+#  distributed with this work for additional information
+#  regarding copyright ownership.  The ASF licenses this file
+#  to you under the Apache License, Version 2.0 (the
+#  "License"); you may not use this file except in compliance
+#  with the License.  You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing, software
+#  distributed under the License is distributed on an "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  See the License for the specific language governing permissions and
+#  limitations under the License.
+
+Test.Summary = '''
+Verify correct URI parsing behavior.
+'''
+
+ts = Test.MakeATSProcess("ts")
+replay_file = "uri.replay.yaml"
+server = Test.MakeVerifierServerProcess("server", replay_file)
+ts.Disk.records_config.update({
+    'proxy.config.diags.debug.enabled': 1,
+    'proxy.config.diags.debug.tags': 'http',
+})
+ts.Disk.remap_config.AddLine(
+    'map / http://127.0.0.1:{0}'.format(server.Variables.http_port)
+)
+tr = Test.AddTestRun("Verify correct URI parsing behavior.")
+tr.Processes.Default.StartBefore(server)
+tr.Processes.Default.StartBefore(ts)
+tr.AddVerifierClientProcess("client", replay_file, 
http_ports=[ts.Variables.port])

Reply via email to