Просмотр исходного кода

Auto merge of #469 - sfackler:backslash-path, r=SimonSapin

Escape backslash in special URL path components

Closes #468

<!-- Reviewable:start -->
---
This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/rust-url/469)
<!-- Reviewable:end -->
bors-servo 7 лет назад
Родитель
Сommit
1cc36c0f61
6 измененных файлов с 32 добавлено и 4 удалено
  1. 1 1
      Cargo.toml
  2. 1 1
      percent_encoding/Cargo.toml
  3. 5 0
      percent_encoding/lib.rs
  4. 1 0
      src/lib.rs
  5. 13 2
      src/parser.rs
  6. 11 0
      tests/unit.rs

+ 1 - 1
Cargo.toml

@@ -2,7 +2,7 @@
 
 name = "url"
 # When updating version, also modify html_root_url in the lib.rs
-version = "1.7.1"
+version = "1.7.2"
 authors = ["The rust-url developers"]
 
 description = "URL library for Rust, based on the WHATWG URL Standard"

+ 1 - 1
percent_encoding/Cargo.toml

@@ -1,6 +1,6 @@
 [package]
 name = "percent-encoding"
-version = "1.0.1"
+version = "1.0.2"
 authors = ["The rust-url developers"]
 description = "Percent encoding and decoding"
 repository = "https://github.com/servo/rust-url/"

+ 5 - 0
percent_encoding/lib.rs

@@ -140,6 +140,11 @@ define_encode_set! {
     /// space, double quote ("), hash (#), inequality qualifiers (<), (>), backtick (`),
     /// question mark (?), and curly brackets ({), (}), percent sign (%), forward slash (/) are
     /// encoded.
+    ///
+    /// # Note
+    ///
+    /// For [special URLs](https://url.spec.whatwg.org/#is-special), the backslash (\) character should
+    /// additionally be escaped, but that is *not* included in this encode set.
     pub PATH_SEGMENT_ENCODE_SET = [DEFAULT_ENCODE_SET] | {'%', '/'}
 }
 

+ 1 - 0
src/lib.rs

@@ -112,6 +112,7 @@ assert_eq!(css_url.as_str(), "http://servo.github.io/rust-url/main.css");
 #[cfg(feature="heapsize")] #[macro_use] extern crate heapsize;
 
 pub extern crate idna;
+#[macro_use]
 pub extern crate percent_encoding;
 
 use encoding::EncodingOverride;

+ 13 - 2
src/parser.rs

@@ -22,6 +22,12 @@ use percent_encoding::{
     PATH_SEGMENT_ENCODE_SET
 };
 
+define_encode_set! {
+    // The backslash (\) character is treated as a path separator in special URLs
+    // so it needs to be additionally escaped in that case.
+    pub SPECIAL_PATH_SEGMENT_ENCODE_SET = [PATH_SEGMENT_ENCODE_SET] | {'\\'}
+}
+
 pub type ParseResult<T> = Result<T, ParseError>;
 
 macro_rules! simple_enum_error {
@@ -1011,8 +1017,13 @@ impl<'a> Parser<'a> {
                     _ => {
                         self.check_url_code_point(c, &input);
                         if self.context == Context::PathSegmentSetter {
-                            self.serialization.extend(utf8_percent_encode(
-                                utf8_c, PATH_SEGMENT_ENCODE_SET));
+                            if scheme_type.is_special() {
+                                self.serialization.extend(utf8_percent_encode(
+                                    utf8_c, SPECIAL_PATH_SEGMENT_ENCODE_SET));
+                            } else {
+                                self.serialization.extend(utf8_percent_encode(
+                                    utf8_c, PATH_SEGMENT_ENCODE_SET));
+                            }
                         } else {
                             self.serialization.extend(utf8_percent_encode(
                                 utf8_c, DEFAULT_ENCODE_SET));

+ 11 - 0
tests/unit.rs

@@ -109,6 +109,17 @@ fn new_directory_paths() {
     }
 }
 
+#[test]
+fn path_backslash_fun() {
+    let mut special_url = "http://foobar.com".parse::<Url>().unwrap();
+    special_url.path_segments_mut().unwrap().push("foo\\bar");
+    assert_eq!(special_url.as_str(), "http://foobar.com/foo%5Cbar");
+
+    let mut nonspecial_url = "thing://foobar.com".parse::<Url>().unwrap();
+    nonspecial_url.path_segments_mut().unwrap().push("foo\\bar");
+    assert_eq!(nonspecial_url.as_str(), "thing://foobar.com/foo\\bar");
+}
+
 #[test]
 fn from_str() {
     assert!("http://testing.com/this".parse::<Url>().is_ok());