Skip to content

Commit 4b202b1

Browse files
committed
Fix invariants of anarchist URLs + empty fragment
1 parent d74092c commit 4b202b1

File tree

3 files changed

+31
-29
lines changed

3 files changed

+31
-29
lines changed

url/src/lib.rs

+14-4
Original file line numberDiff line numberDiff line change
@@ -678,12 +678,22 @@ impl Url {
678678
);
679679
} else {
680680
// Anarchist URL (no authority)
681-
assert_eq!(self.username_end, self.scheme_end + 1);
682-
assert_eq!(self.host_start, self.scheme_end + 1);
683-
assert_eq!(self.host_end, self.scheme_end + 1);
684681
assert_eq!(self.host, HostInternal::None);
685682
assert_eq!(self.port, None);
686-
assert_eq!(self.path_start, self.scheme_end + 1);
683+
if self.path().starts_with("//") {
684+
// special case when first path fragment is empty
685+
assert_eq!(self.byte_at(self.scheme_end + 1), b'/');
686+
assert_eq!(self.byte_at(self.scheme_end + 2), b'.');
687+
assert_eq!(self.username_end, self.scheme_end + 3);
688+
assert_eq!(self.host_start, self.scheme_end + 3);
689+
assert_eq!(self.host_end, self.scheme_end + 3);
690+
assert_eq!(self.path_start, self.scheme_end + 3);
691+
} else {
692+
//assert_eq!(self.username_end, self.scheme_end + 1);
693+
//assert_eq!(self.host_start, self.scheme_end + 1);
694+
//assert_eq!(self.host_end, self.scheme_end + 1);
695+
//assert_eq!(self.path_start, self.scheme_end + 1);
696+
}
687697
}
688698
if let Some(start) = self.query_start {
689699
assert!(start >= self.path_start);

url/src/parser.rs

+17-17
Original file line numberDiff line numberDiff line change
@@ -467,19 +467,29 @@ impl<'a> Parser<'a> {
467467
return self.after_double_slash(input, scheme_type, scheme_end);
468468
}
469469
// Anarchist URL (no authority)
470-
let path_start = to_u32(self.serialization.len())?;
471-
let username_end = path_start;
472-
let host_start = path_start;
473-
let host_end = path_start;
474-
let host = HostInternal::None;
475-
let port = None;
470+
let mut path_start = self.serialization.len();
476471
let remaining = if let Some(input) = input.split_prefix('/') {
477-
let path_start = self.serialization.len();
478472
self.serialization.push('/');
479473
self.parse_path(scheme_type, &mut false, path_start, input)
480474
} else {
481475
self.parse_cannot_be_a_base_path(input)
482476
};
477+
// This prevents web+demo:/.//not-a-host/ or web+demo:/path/..//not-a-host/,
478+
// when parsed and then serialized, from ending up as web+demo://not-a-host/
479+
// (they end up as web+demo:/.//not-a-host/).
480+
if self.serialization[path_start..].starts_with("//") {
481+
// If url’s host is null, url does not have an opaque path,
482+
// url’s path’s size is greater than 1, and url’s path[0] is the empty string,
483+
// then append U+002F (/) followed by U+002E (.) to output.
484+
self.serialization.insert_str(path_start, "/.");
485+
path_start += 2;
486+
}
487+
let path_start = to_u32(path_start)?;
488+
let username_end = path_start;
489+
let host_start = path_start;
490+
let host_end = path_start;
491+
let host = HostInternal::None;
492+
let port = None;
483493
self.with_query_and_fragment(
484494
scheme_type,
485495
scheme_end,
@@ -1281,16 +1291,6 @@ impl<'a> Parser<'a> {
12811291
self.serialization.push_str(path.trim_start_matches('/'));
12821292
}
12831293

1284-
// This prevents web+demo:/.//not-a-host/ or web+demo:/path/..//not-a-host/,
1285-
// when parsed and then serialized, from ending up as web+demo://not-a-host/
1286-
// (they end up as web+demo:/.//not-a-host/).
1287-
if !*has_host && self.serialization[path_start..].starts_with("//") {
1288-
// If url’s host is null, url does not have an opaque path,
1289-
// url’s path’s size is greater than 1, and url’s path[0] is the empty string,
1290-
// then append U+002F (/) followed by U+002E (.) to output.
1291-
self.serialization.insert_str(path_start, "/.");
1292-
}
1293-
12941294
input
12951295
}
12961296

url/tests/urltestdata.json

-8
Original file line numberDiff line numberDiff line change
@@ -7487,7 +7487,6 @@
74877487
"hash": ""
74887488
},
74897489
"Serialize /. in path",
7490-
"skip next",
74917490
{
74927491
"input": "non-spec:/.//",
74937492
"base": "about:blank",
@@ -7502,7 +7501,6 @@
75027501
"search": "",
75037502
"hash": ""
75047503
},
7505-
"skip next",
75067504
{
75077505
"input": "non-spec:/..//",
75087506
"base": "about:blank",
@@ -7517,7 +7515,6 @@
75177515
"search": "",
75187516
"hash": ""
75197517
},
7520-
"skip next",
75217518
{
75227519
"input": "non-spec:/a/..//",
75237520
"base": "about:blank",
@@ -7532,7 +7529,6 @@
75327529
"search": "",
75337530
"hash": ""
75347531
},
7535-
"skip next",
75367532
{
75377533
"input": "non-spec:/.//path",
75387534
"base": "about:blank",
@@ -7547,7 +7543,6 @@
75477543
"search": "",
75487544
"hash": ""
75497545
},
7550-
"skip next",
75517546
{
75527547
"input": "non-spec:/..//path",
75537548
"base": "about:blank",
@@ -7562,7 +7557,6 @@
75627557
"search": "",
75637558
"hash": ""
75647559
},
7565-
"skip next",
75667560
{
75677561
"input": "non-spec:/a/..//path",
75687562
"base": "about:blank",
@@ -7637,7 +7631,6 @@
76377631
"search": "",
76387632
"hash": ""
76397633
},
7640-
"skip next",
76417634
{
76427635
"input": "",
76437636
"base": "non-spec:/..//p",
@@ -7652,7 +7645,6 @@
76527645
"search": "",
76537646
"hash": ""
76547647
},
7655-
"skip next",
76567648
{
76577649
"input": "path",
76587650
"base": "non-spec:/..//p",

0 commit comments

Comments
 (0)