Prechádzať zdrojové kódy

Add a scheme setter

Simon Sapin 10 rokov pred
rodič
commit
c9e687cf2f
3 zmenil súbory, kde vykonal 51 pridanie a 10 odobranie
  1. 38 7
      src/lib.rs
  2. 10 0
      src/parser.rs
  3. 3 3
      src/webidl.rs

+ 38 - 7
src/lib.rs

@@ -420,13 +420,7 @@ impl Url {
     }
 
     fn mutate<F: FnOnce(&mut Parser) -> R, R>(&mut self, f: F) -> R {
-        let mut parser = Parser {
-            serialization: mem::replace(&mut self.serialization, String::new()),
-            base_url: None,
-            query_encoding_override: EncodingOverride::utf8(),
-            log_syntax_violation: None,
-            context: Context::Setter,
-        };
+        let mut parser = Parser::for_setter(mem::replace(&mut self.serialization, String::new()));
         let result = f(&mut parser);
         self.serialization = parser.serialization;
         result
@@ -477,6 +471,43 @@ impl Url {
         }
     }
 
+    /// Change this URL’s scheme.
+    ///
+    /// Do nothing and return `Err` if:
+    /// * The new scheme is not in `[a-zA-Z][a-zA-Z0-9+.-]+`
+    /// * This URL is non-relative and the new scheme is one of
+    ///   `http`, `https`, `ws`, `wss`, `ftp`, or `gopher`
+    pub fn set_scheme(&mut self, scheme: &str) -> Result<(), ()> {
+        self.set_scheme_internal(scheme, false)
+    }
+
+    fn set_scheme_internal(&mut self, scheme: &str, allow_extra_input_after_colon: bool)
+                          -> Result<(), ()> {
+        let mut parser = Parser::for_setter(String::new());
+        let remaining = try!(parser.parse_scheme(scheme));
+        if !(remaining.is_empty() || allow_extra_input_after_colon) {
+            return Err(())
+        }
+        let old_scheme_end = self.scheme_end;
+        let new_scheme_end = to_u32(parser.serialization.len()).unwrap();
+        let adjust = |index: &mut u32| {
+            *index -= old_scheme_end;
+            *index += new_scheme_end;
+        };
+
+        self.scheme_end = new_scheme_end;
+        adjust(&mut self.username_end);
+        adjust(&mut self.host_start);
+        adjust(&mut self.host_end);
+        adjust(&mut self.path_start);
+        if let Some(ref mut index) = self.query_start { adjust(index) }
+        if let Some(ref mut index) = self.fragment_start { adjust(index) }
+
+        parser.serialization.push_str(self.slice(old_scheme_end..));
+        self.serialization = parser.serialization;
+        Ok(())
+    }
+
     /// Convert a file name as `std::path::Path` into an URL in the `file` scheme.
     ///
     /// This returns `Err` if the given path is not absolute or,

+ 10 - 0
src/parser.rs

@@ -113,6 +113,16 @@ pub enum Context {
 }
 
 impl<'a> Parser<'a> {
+    pub fn for_setter(serialization: String) -> Parser<'a> {
+        Parser {
+            serialization: serialization,
+            base_url: None,
+            query_encoding_override: EncodingOverride::utf8(),
+            log_syntax_violation: None,
+            context: Context::Setter,
+        }
+    }
+
     fn syntax_violation(&self, reason: &'static str) {
         if let Some(log) = self.log_syntax_violation {
             log(reason)

+ 3 - 3
src/webidl.rs

@@ -43,9 +43,9 @@ impl WebIdl {
         url.slice(..url.scheme_end + 1)
     }
 
-    /// **Not implemented yet** Setter for https://url.spec.whatwg.org/#dom-url-protocol
-    pub fn set_protocol(_url: &mut Url, _new_protocol: &str) {
-        unimplemented!()  // FIXME
+    /// Setter for https://url.spec.whatwg.org/#dom-url-protocol
+    pub fn set_protocol(url: &mut Url, new_protocol: &str) {
+        let _ = url.set_scheme_internal(new_protocol, true);
     }
 
     /// Getter for https://url.spec.whatwg.org/#dom-url-username