Skip to content

Commit 15418b4

Browse files
committed
Path and file parsing.
1 parent c9c1432 commit 15418b4

File tree

6 files changed

+332
-61
lines changed

6 files changed

+332
-61
lines changed

src/host.rs

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,52 @@ pub(crate) enum HostInternal {
2424
Ipv6(Ipv6Addr),
2525
}
2626

27-
impl<S> From<Host<S>> for HostInternal {
27+
#[cfg(feature = "serde")]
28+
impl ::serde::Serialize for HostInternal {
29+
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
30+
where
31+
S: ::serde::Serializer,
32+
{
33+
// This doesn’t use `derive` because that involves
34+
// large dependencies (that take a long time to build), and
35+
// either Macros 1.1 which are not stable yet or a cumbersome build script.
36+
//
37+
// Implementing `Serializer` correctly for an enum is tricky,
38+
// so let’s use existing enums that already do.
39+
use std::net::IpAddr;
40+
match *self {
41+
HostInternal::None => None,
42+
HostInternal::Domain => Some(None),
43+
HostInternal::Ipv4(addr) => Some(Some(IpAddr::V4(addr))),
44+
HostInternal::Ipv6(addr) => Some(Some(IpAddr::V6(addr))),
45+
}
46+
.serialize(serializer)
47+
}
48+
}
49+
50+
#[cfg(feature = "serde")]
51+
impl<'de> ::serde::Deserialize<'de> for HostInternal {
52+
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
53+
where
54+
D: ::serde::Deserializer<'de>,
55+
{
56+
use std::net::IpAddr;
57+
Ok(match ::serde::Deserialize::deserialize(deserializer)? {
58+
None => HostInternal::None,
59+
Some(None) => HostInternal::Domain,
60+
Some(Some(IpAddr::V4(addr))) => HostInternal::Ipv4(addr),
61+
Some(Some(IpAddr::V6(addr))) => HostInternal::Ipv6(addr),
62+
})
63+
}
64+
}
65+
66+
impl<S> From<Host<S>> for HostInternal
67+
where
68+
S: ToString,
69+
{
2870
fn from(host: Host<S>) -> HostInternal {
2971
match host {
72+
Host::Domain(ref s) if s.to_string().is_empty() => HostInternal::None,
3073
Host::Domain(_) => HostInternal::Domain,
3174
Host::Ipv4(address) => HostInternal::Ipv4(address),
3275
Host::Ipv6(address) => HostInternal::Ipv6(address),

src/lib.rs

Lines changed: 30 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -456,13 +456,15 @@ impl Url {
456456

457457
if self.slice(self.scheme_end + 1..).starts_with("//") {
458458
// URL with authority
459-
match self.byte_at(self.username_end) {
460-
b':' => {
461-
assert!(self.host_start >= self.username_end + 2);
462-
assert_eq!(self.byte_at(self.host_start - 1), b'@');
459+
if self.username_end < self.serialization.len() as u32 {
460+
match self.byte_at(self.username_end) {
461+
b':' => {
462+
assert!(self.host_start >= self.username_end + 2);
463+
assert_eq!(self.byte_at(self.host_start - 1), b'@');
464+
}
465+
b'@' => assert!(self.host_start == self.username_end + 1),
466+
_ => assert_eq!(self.username_end, self.scheme_end + 3),
463467
}
464-
b'@' => assert!(self.host_start == self.username_end + 1),
465-
_ => assert_eq!(self.username_end, self.scheme_end + 3),
466468
}
467469
assert!(self.host_start >= self.username_end);
468470
assert!(self.host_end >= self.host_start);
@@ -490,7 +492,12 @@ impl Url {
490492
Some(port_str.parse::<u16>().expect("Couldn't parse port?"))
491493
);
492494
}
493-
assert_eq!(self.byte_at(self.path_start), b'/');
495+
assert!(
496+
self.path_start as usize == self.serialization.len()
497+
|| self.byte_at(self.path_start) == b'/'
498+
|| self.byte_at(self.path_start) == b'#'
499+
|| self.byte_at(self.path_start) == b'?'
500+
);
494501
} else {
495502
// Anarchist URL (no authority)
496503
assert_eq!(self.username_end, self.scheme_end + 1);
@@ -501,11 +508,11 @@ impl Url {
501508
assert_eq!(self.path_start, self.scheme_end + 1);
502509
}
503510
if let Some(start) = self.query_start {
504-
assert!(start > self.path_start);
511+
assert!(start >= self.path_start);
505512
assert_eq!(self.byte_at(start), b'?');
506513
}
507514
if let Some(start) = self.fragment_start {
508-
assert!(start > self.path_start);
515+
assert!(start >= self.path_start);
509516
assert_eq!(self.byte_at(start), b'#');
510517
}
511518
if let (Some(query_start), Some(fragment_start)) = (self.query_start, self.fragment_start) {
@@ -745,7 +752,10 @@ impl Url {
745752
pub fn password(&self) -> Option<&str> {
746753
// This ':' is not the one marking a port number since a host can not be empty.
747754
// (Except for file: URLs, which do not have port numbers.)
748-
if self.has_authority() && self.byte_at(self.username_end) == b':' {
755+
if self.has_authority()
756+
&& self.username_end < self.serialization.len() as u32
757+
&& self.byte_at(self.username_end) == b':'
758+
{
749759
debug_assert!(self.byte_at(self.host_start - 1) == b'@');
750760
Some(self.slice(self.username_end + 1..self.host_start - 1))
751761
} else {
@@ -1226,7 +1236,7 @@ impl Url {
12261236
if let Some(input) = fragment {
12271237
self.fragment_start = Some(to_u32(self.serialization.len()).unwrap());
12281238
self.serialization.push('#');
1229-
self.mutate(|parser| parser.parse_fragment(parser::Input::new(input)))
1239+
self.mutate(|parser| parser.parse_fragment(parser::Input::no_trim(input)))
12301240
} else {
12311241
self.fragment_start = None
12321242
}
@@ -1284,7 +1294,11 @@ impl Url {
12841294
let scheme_type = SchemeType::from(self.scheme());
12851295
let scheme_end = self.scheme_end;
12861296
self.mutate(|parser| {
1287-
parser.parse_query(scheme_type, scheme_end, parser::Input::new(input))
1297+
parser.parse_query(
1298+
scheme_type,
1299+
scheme_end,
1300+
parser::Input::trim_tab_and_newlines(input),
1301+
)
12881302
});
12891303
}
12901304

@@ -1390,8 +1404,12 @@ impl Url {
13901404
}
13911405
parser.parse_cannot_be_a_base_path(parser::Input::new(path));
13921406
} else {
1407+
let path_start = parser.serialization.len();
13931408
let mut has_host = true; // FIXME
13941409
parser.parse_path_start(scheme_type, &mut has_host, parser::Input::new(path));
1410+
if scheme_type.is_file() {
1411+
parser::trim_path(&mut parser.serialization, path_start);
1412+
}
13951413
}
13961414
});
13971415
self.restore_after_path(old_after_path_pos, &after_path);

0 commit comments

Comments
 (0)