Simon Sapin 10 лет назад
Родитель
Сommit
06f2fafa3f
3 измененных файлов с 32 добавлено и 13 удалено
  1. 6 2
      src/lib.rs
  2. 11 8
      src/parser.rs
  3. 15 3
      src/webidl.rs

+ 6 - 2
src/lib.rs

@@ -567,12 +567,17 @@ impl Url {
     /// If this URL is non-relative, does not have a host, or has the `file` scheme;
     /// do nothing and return `Err`.
     pub fn set_port(&mut self, mut port: Option<u16>) -> Result<(), ()> {
-        if self.non_relative() {
+        if !self.has_host() || self.scheme() == "file" {
             return Err(())
         }
         if port.is_some() && port == parser::default_port(self.scheme()) {
             port = None
         }
+        self.set_port_inner(port);
+        Ok(())
+    }
+
+    fn set_port_inner(&mut self, port: Option<u16>) {
         match (self.port, port) {
             (None, None) => {}
             (Some(_), None) => {
@@ -602,7 +607,6 @@ impl Url {
                 self.serialization.push_str(&path_and_after);
             }
         }
-        Ok(())
     }
 
     /// Change this URL’s host.

+ 11 - 8
src/parser.rs

@@ -606,10 +606,15 @@ impl<'a> Parser<'a> {
         let (host, remaining) = try!(self.parse_host(input, scheme_type));
         let host_end = try!(to_u32(self.serialization.len()));
         let (port, remaining) = if remaining.starts_with(":") {
-            try!(self.parse_port(&remaining[1..], scheme_end))
+            let syntax_violation = |message| self.syntax_violation(message);
+            let scheme = || default_port(&self.serialization[..scheme_end as usize]);
+            try!(Parser::parse_port(&remaining[1..], syntax_violation, scheme))
         } else {
             (None, remaining)
         };
+        if let Some(port) = port {
+            write!(&mut self.serialization, ":{}", port).unwrap()
+        }
         Ok((host_end, host, port, remaining))
     }
 
@@ -696,8 +701,9 @@ impl<'a> Parser<'a> {
         Ok((true, host, &input[end..]))
     }
 
-    pub fn parse_port<'i>(&mut self, input: &'i str, scheme_end: u32)
-                          -> ParseResult<(Option<u16>, &'i str)> {
+    pub fn parse_port<'i, V, P>(input: &'i str, syntax_violation: V, default_port: P)
+                                -> ParseResult<(Option<u16>, &'i str)>
+                                where V: Fn(&'static str), P: Fn() -> Option<u16> {
         let mut port = 0;
         let mut has_any_digit = false;
         let mut end = input.len();
@@ -714,17 +720,14 @@ impl<'a> Parser<'a> {
                         end = i;
                         break
                     },
-                    '\t' | '\n' | '\r' => self.syntax_violation("invalid character"),
+                    '\t' | '\n' | '\r' => syntax_violation("invalid character"),
                     _ => return Err(ParseError::InvalidPort)
                 }
             }
         }
         let mut opt_port = Some(port as u16);
-        if !has_any_digit || opt_port == default_port(&self.serialization[..scheme_end as usize]) {
+        if !has_any_digit || opt_port == default_port() {
             opt_port = None;
-        } else {
-            self.serialization.push(':');
-            write!(&mut self.serialization, "{}", port).unwrap();
         }
         return Ok((opt_port, &input[end..]))
     }

+ 15 - 3
src/webidl.rs

@@ -9,6 +9,7 @@
 use {Url, ParseError};
 use host::Host;
 use idna::domain_to_unicode;
+use parser::{Parser, default_port};
 
 /// https://url.spec.whatwg.org/#api
 pub struct WebIdl;
@@ -115,9 +116,20 @@ impl WebIdl {
         }
     }
 
-    /// **Not implemented yet** Setter for https://url.spec.whatwg.org/#dom-url-port
-    pub fn set_port(_url: &mut Url, _new_port: &str) {
-        unimplemented!()  // FIXME
+    /// Setter for https://url.spec.whatwg.org/#dom-url-port
+    pub fn set_port(url: &mut Url, new_port: &str) {
+        let result;
+        {
+            // has_host implies !non_relative
+            let scheme = url.scheme();
+            if !url.has_host() || scheme == "file" {
+                return
+            }
+            result = Parser::parse_port(new_port, |_| (), || default_port(scheme))
+        }
+        if let Ok((new_port, _remaining)) = result {
+            url.set_port_inner(new_port)
+        }
     }
 
     /// Getter for https://url.spec.whatwg.org/#dom-url-pathname