Repository: servo/rust-url (rust)

Issue:
Calling `quirks::set_port()` with invalid prefix characters unset the port (WPT non-compliance)
In browsers (tested on Chrome, Firefox and Safari), doing the following:

```js
const u = new URL("https://example.com:8000");
u.port = "\u00009000";
console.log(u.port);
```

will show port `8000` (unchanged). This is also tested in the WPT suite here: https://github.com/web-platform-tests/wpt/blob/2a64dae4641fbd61bd4257df460e188f425b492e/url/url-setters-stripping.any.js#L85-L91. That's how the bug came to my attention.

Doing the same using:

```rust
let mut url = url::Url::parse("http://example.com:8000").unwrap();
url::quirks::set_port(&mut url, "\u{0000}9000").unwrap();
assert_eq!(url.port(), Some(8000));
```

will panic with `url.port()` returning `None`.

Pull request description:
Add a test for and fix issue #974
Fixes #974.

Patch:
diff --git a/url/src/parser.rs b/url/src/parser.rs
index 8dd054d..181a02e 100644
--- a/url/src/parser.rs
+++ b/url/src/parser.rs
@@ -1120,6 +1120,11 @@ impl<'a> Parser<'a> {
             }
             input = remaining;
         }
+
+        if !has_any_digit && context == Context::Setter && !input.is_empty() {
+            return Err(ParseError::InvalidPort);
+        }
+
         let mut opt_port = Some(port as u16);
         if !has_any_digit || opt_port == default_port() {
             opt_port = None;


Test patch:
diff --git a/url/tests/expected_failures.txt b/url/tests/expected_failures.txt
index 91145db..899e7f7 100644
--- a/url/tests/expected_failures.txt
+++ b/url/tests/expected_failures.txt
@@ -39,7 +39,6 @@
 <non-spec:/.//p> set hostname to <h>
 <non-spec:/.//p> set hostname to <>
 <foo:///some/path> set pathname to <>
-<http://example.net:8080/path> set port to <randomstring>
 <file:///var/log/system.log> set href to <http://0300.168.0xF0>
 <file://monkey/> set pathname to <\\\\>
 <file:///unicorn> set pathname to <//\\/>
diff --git a/url/tests/unit.rs b/url/tests/unit.rs
index afe842b..fd9a3ce 100644
--- a/url/tests/unit.rs
+++ b/url/tests/unit.rs
@@ -1316,3 +1316,10 @@ fn issue_864() {
     url.set_path("x");
     dbg!(&url);
 }
+
+#[test]
+fn issue_974() {
+    let mut url = url::Url::parse("http://example.com:8000").unwrap();
+    let _ = url::quirks::set_port(&mut url, "\u{0000}9000");
+    assert_eq!(url.port(), Some(8000));
+}