Explorar o código

Normalize URL paths: convert /.//p, /..//p, and //p to p (#943)

Sean Kim hai 1 ano
pai
achega
b08a655d07
Modificáronse 2 ficheiros con 53 adicións e 5 borrados
  1. 53 1
      url/src/lib.rs
  2. 0 4
      url/tests/expected_failures.txt

+ 53 - 1
url/src/lib.rs

@@ -1742,6 +1742,39 @@ impl Url {
         let old_after_path_pos = to_u32(self.serialization.len()).unwrap();
         let old_after_path_pos = to_u32(self.serialization.len()).unwrap();
         let cannot_be_a_base = self.cannot_be_a_base();
         let cannot_be_a_base = self.cannot_be_a_base();
         let scheme_type = SchemeType::from(self.scheme());
         let scheme_type = SchemeType::from(self.scheme());
+        let mut path_empty = false;
+
+        // Check ':' and then see if the next character is '/'
+        let mut has_host = if let Some(index) = self.serialization.find(":") {
+            if self.serialization.len() > index + 1
+                && self.serialization.as_bytes().get(index + 1) == Some(&b'/')
+            {
+                let rest = &self.serialization[(index + ":/".len())..];
+                let host_part = rest.split('/').next().unwrap_or("");
+                path_empty = rest.is_empty();
+                !host_part.is_empty() && !host_part.contains('@')
+            } else {
+                false
+            }
+        } else {
+            false
+        };
+
+        // Ensure the path length is greater than 1 to account
+        // for cases where "/." is already appended from serialization
+        // If we set path, then we already checked the other two conditions:
+        // https://url.spec.whatwg.org/#url-serializing
+        // 1. The host is null
+        // 2. the first segment of the URL's path is an empty string
+        if path.len() > 1 {
+            if let Some(index) = self.serialization.find(":") {
+                let removal_start = index + ":".len();
+                if self.serialization[removal_start..].starts_with("/.") {
+                    self.path_start -= "/.".len() as u32;
+                }
+            }
+        }
+
         self.serialization.truncate(self.path_start as usize);
         self.serialization.truncate(self.path_start as usize);
         self.mutate(|parser| {
         self.mutate(|parser| {
             if cannot_be_a_base {
             if cannot_be_a_base {
@@ -1751,7 +1784,6 @@ impl Url {
                 }
                 }
                 parser.parse_cannot_be_a_base_path(parser::Input::new_no_trim(path));
                 parser.parse_cannot_be_a_base_path(parser::Input::new_no_trim(path));
             } else {
             } else {
-                let mut has_host = true; // FIXME
                 parser.parse_path_start(
                 parser.parse_path_start(
                     scheme_type,
                     scheme_type,
                     &mut has_host,
                     &mut has_host,
@@ -1759,6 +1791,26 @@ impl Url {
                 );
                 );
             }
             }
         });
         });
+
+        // For cases where normalization is applied across both the serialization and the path.
+        // Append "/." immediately after the scheme (up to ":")
+        // This is done if three conditions are met.
+        // https://url.spec.whatwg.org/#url-serializing
+        // 1. The host is null
+        // 2. The url's path length is greater than 1
+        // 3. the first segment of the URL's path is an empty string
+        if !has_host && path.len() > 1 && path_empty {
+            if let Some(index) = self.serialization.find(":") {
+                if self.serialization.len() > index + 2
+                    && self.serialization.as_bytes().get(index + 1) == Some(&b'/')
+                    && self.serialization.as_bytes().get(index + 2) == Some(&b'/')
+                {
+                    self.serialization.insert_str(index + ":".len(), "/.");
+                    self.path_start += "/.".len() as u32;
+                }
+            }
+        }
+
         self.restore_after_path(old_after_path_pos, &after_path);
         self.restore_after_path(old_after_path_pos, &after_path);
     }
     }
 
 

+ 0 - 4
url/tests/expected_failures.txt

@@ -43,7 +43,3 @@
 <file://monkey/> set pathname to <\\\\>
 <file://monkey/> set pathname to <\\\\>
 <file:///unicorn> set pathname to <//\\/>
 <file:///unicorn> set pathname to <//\\/>
 <file:///unicorn> set pathname to <//monkey/..//>
 <file:///unicorn> set pathname to <//monkey/..//>
-<non-spec:/> set pathname to </.//p>
-<non-spec:/> set pathname to </..//p>
-<non-spec:/> set pathname to <//p>
-<non-spec:/.//> set pathname to <p>