Skip to content

Commit 0777230

Browse files
committed
update Uri parser
1 parent 84c7030 commit 0777230

File tree

1 file changed

+112
-70
lines changed

1 file changed

+112
-70
lines changed

src/uri.rs

Lines changed: 112 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -229,16 +229,10 @@ impl<'a> Uri<'a> {
229229
///assert_eq!(uri.resource(), "/bar/baz?query#fragment");
230230
///```
231231
pub fn resource(&self) -> &str {
232-
let mut result = "/";
233-
234-
for v in &[self.path, self.query, self.fragment] {
235-
if let Some(r) = v {
236-
result = &self.inner[r.start..];
237-
break;
238-
}
232+
match self.path {
233+
Some(p) => &self.inner[p.start..],
234+
None => "/",
239235
}
240-
241-
result
242236
}
243237
}
244238

@@ -265,30 +259,38 @@ impl<'a> TryFrom<&'a str> for Uri<'a> {
265259
fn try_from(s: &'a str) -> Result<Self, Self::Error> {
266260
let (scheme, mut uri_part) = get_chunks(&s, Some(RangeC::new(0, s.len())), ":");
267261
let scheme = scheme.ok_or(ParseErr::UriErr)?;
262+
let (mut authority, mut query, mut fragment) = (None, None, None);
268263

269-
let mut authority = None;
270-
271-
if let Some(u) = &uri_part {
272-
if s[*u].contains("//") {
264+
if let Some(u) = uri_part {
265+
if s[u].contains("//") {
273266
let (auth, part) = get_chunks(&s, Some(RangeC::new(u.start + 2, u.end)), "/");
274267

275-
authority = if let Some(a) = auth {
276-
Some(Authority::try_from(&s[a])?)
277-
} else {
278-
None
268+
if let Some(a) = auth {
269+
authority = Some(Authority::try_from(&s[a])?)
279270
};
280271

281272
uri_part = part;
282273
}
283274
}
284275

285-
let (mut path, uri_part) = get_chunks(&s, uri_part, "?");
286-
287-
if authority.is_some() || &s[scheme] == "file" {
288-
path = path.map(|p| RangeC::new(p.start - 1, p.end));
276+
if let Some(u) = uri_part {
277+
if &s[u.start - 1..u.start] == "/" {
278+
uri_part = Some(RangeC::new(u.start - 1, u.end));
279+
}
289280
}
290281

291-
let (query, fragment) = get_chunks(&s, uri_part, "#");
282+
let mut path = uri_part;
283+
284+
if let Some(u) = uri_part {
285+
if s[u].contains("?") && s[u].contains("#") {
286+
(path, uri_part) = get_chunks(&s, uri_part, "?");
287+
(query, fragment) = get_chunks(&s, uri_part, "#");
288+
} else if s[u].contains("?") {
289+
(path, query) = get_chunks(&s, uri_part, "?");
290+
} else if s[u].contains("#") {
291+
(path, fragment) = get_chunks(&s, uri_part, "#");
292+
}
293+
}
292294

293295
Ok(Uri {
294296
inner: s,
@@ -405,17 +407,14 @@ impl<'a> TryFrom<&'a str> for Authority<'a> {
405407

406408
let uri_part = if s.contains('@') {
407409
let (info, part) = get_chunks(&s, Some(RangeC::new(0, s.len())), "@");
408-
let (name, pass) = get_chunks(&s, info, ":");
409-
410-
username = name;
411-
password = pass;
410+
(username, password) = get_chunks(&s, info, ":");
412411

413412
part
414413
} else {
415414
Some(RangeC::new(0, s.len()))
416415
};
417416

418-
let split_by = if s.contains(']') && s.contains('[') {
417+
let split_by = if s.contains('[') && s.contains(']') {
419418
"]:"
420419
} else {
421420
":"
@@ -498,12 +497,14 @@ fn get_chunks<'a>(
498497
mod tests {
499498
use super::*;
500499

501-
const TEST_URIS: [&str; 5] = [
500+
const TEST_URIS: [&str; 7] = [
502501
"https://user:info@foo.com:12/bar/baz?query#fragment",
503502
"file:///C:/Users/User/Pictures/screenshot.png",
504503
"https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol",
505504
"mailto:John.Doe@example.com",
506505
"https://[4b10:bbb0:0:d0::ba7:8001]:443/",
506+
"http://example.com/?query=val",
507+
"https://example.com/#fragment",
507508
];
508509

509510
const TEST_AUTH: [&str; 4] = [
@@ -552,12 +553,11 @@ mod tests {
552553
.iter()
553554
.map(|uri| Uri::try_from(*uri).unwrap())
554555
.collect();
556+
const RESULT: [&str; 7] = ["https", "file", "https", "mailto", "https", "http", "https"];
555557

556-
assert_eq!(uris[0].scheme(), "https");
557-
assert_eq!(uris[1].scheme(), "file");
558-
assert_eq!(uris[2].scheme(), "https");
559-
assert_eq!(uris[3].scheme(), "mailto");
560-
assert_eq!(uris[4].scheme(), "https");
558+
for i in 0..RESULT.len() {
559+
assert_eq!(uris[i].scheme(), RESULT[i]);
560+
}
561561
}
562562

563563
#[test]
@@ -566,12 +566,11 @@ mod tests {
566566
.iter()
567567
.map(|uri| Uri::try_from(*uri).unwrap())
568568
.collect();
569+
const RESULT: [Option<&str>; 7] = [Some("user:info"), None, None, None, None, None, None];
569570

570-
assert_eq!(uris[0].user_info(), Some("user:info"));
571-
assert_eq!(uris[1].user_info(), None);
572-
assert_eq!(uris[2].user_info(), None);
573-
assert_eq!(uris[3].user_info(), None);
574-
assert_eq!(uris[4].user_info(), None);
571+
for i in 0..RESULT.len() {
572+
assert_eq!(uris[i].user_info(), RESULT[i]);
573+
}
575574
}
576575

577576
#[test]
@@ -581,11 +580,19 @@ mod tests {
581580
.map(|uri| Uri::try_from(*uri).unwrap())
582581
.collect();
583582

584-
assert_eq!(uris[0].host(), Some("foo.com"));
585-
assert_eq!(uris[1].host(), None);
586-
assert_eq!(uris[2].host(), Some("en.wikipedia.org"));
587-
assert_eq!(uris[3].host(), None);
588-
assert_eq!(uris[4].host(), Some("[4b10:bbb0:0:d0::ba7:8001]"));
583+
const RESULT: [Option<&str>; 7] = [
584+
Some("foo.com"),
585+
None,
586+
Some("en.wikipedia.org"),
587+
None,
588+
Some("[4b10:bbb0:0:d0::ba7:8001]"),
589+
Some("example.com"),
590+
Some("example.com"),
591+
];
592+
593+
for i in 0..RESULT.len() {
594+
assert_eq!(uris[i].host(), RESULT[i]);
595+
}
589596
}
590597

591598
#[test]
@@ -612,7 +619,11 @@ mod tests {
612619
assert_eq!(uris[0].port(), Some(12));
613620
assert_eq!(uris[4].port(), Some(443));
614621

615-
for i in 1..3 {
622+
for i in 1..4 {
623+
assert_eq!(uris[i].port(), None);
624+
}
625+
626+
for i in 5..7 {
616627
assert_eq!(uris[i].port(), None);
617628
}
618629
}
@@ -624,11 +635,13 @@ mod tests {
624635
.map(|uri| Uri::try_from(*uri).unwrap())
625636
.collect();
626637

627-
assert_eq!(uris[0].corr_port(), 12);
628-
assert_eq!(uris[1].corr_port(), HTTP_PORT);
629-
assert_eq!(uris[2].corr_port(), HTTPS_PORT);
630-
assert_eq!(uris[3].corr_port(), HTTP_PORT);
631-
assert_eq!(uris[4].corr_port(), HTTPS_PORT);
638+
const RESULT: [u16; 7] = [
639+
12, HTTP_PORT, HTTPS_PORT, HTTP_PORT, HTTPS_PORT, HTTP_PORT, HTTPS_PORT,
640+
];
641+
642+
for i in 0..RESULT.len() {
643+
assert_eq!(uris[i].corr_port(), RESULT[i]);
644+
}
632645
}
633646

634647
#[test]
@@ -638,14 +651,19 @@ mod tests {
638651
.map(|uri| Uri::try_from(*uri).unwrap())
639652
.collect();
640653

641-
assert_eq!(uris[0].path(), Some("/bar/baz"));
642-
assert_eq!(
643-
uris[1].path(),
644-
Some("/C:/Users/User/Pictures/screenshot.png")
645-
);
646-
assert_eq!(uris[2].path(), Some("/wiki/Hypertext_Transfer_Protocol"));
647-
assert_eq!(uris[3].path(), Some("John.Doe@example.com"));
648-
assert_eq!(uris[4].path(), None);
654+
const RESULT: [Option<&str>; 7] = [
655+
Some("/bar/baz"),
656+
Some("/C:/Users/User/Pictures/screenshot.png"),
657+
Some("/wiki/Hypertext_Transfer_Protocol"),
658+
Some("John.Doe@example.com"),
659+
None,
660+
Some("/"),
661+
Some("/"),
662+
];
663+
664+
for i in 0..RESULT.len() {
665+
assert_eq!(uris[i].path(), RESULT[i]);
666+
}
649667
}
650668

651669
#[test]
@@ -655,10 +673,18 @@ mod tests {
655673
.map(|uri| Uri::try_from(*uri).unwrap())
656674
.collect();
657675

658-
assert_eq!(uris[0].query(), Some("query"));
659-
660-
for i in 1..4 {
661-
assert_eq!(uris[i].query(), None);
676+
const RESULT: [Option<&str>; 7] = [
677+
Some("query"),
678+
None,
679+
None,
680+
None,
681+
None,
682+
Some("query=val"),
683+
None,
684+
];
685+
686+
for i in 0..RESULT.len() {
687+
assert_eq!(uris[i].query(), RESULT[i]);
662688
}
663689
}
664690

@@ -669,10 +695,18 @@ mod tests {
669695
.map(|uri| Uri::try_from(*uri).unwrap())
670696
.collect();
671697

672-
assert_eq!(uris[0].fragment(), Some("fragment"));
673-
674-
for i in 1..4 {
675-
assert_eq!(uris[i].fragment(), None);
698+
const RESULT: [Option<&str>; 7] = [
699+
Some("fragment"),
700+
None,
701+
None,
702+
None,
703+
None,
704+
None,
705+
Some("fragment"),
706+
];
707+
708+
for i in 0..RESULT.len() {
709+
assert_eq!(uris[i].fragment(), RESULT[i]);
676710
}
677711
}
678712

@@ -683,11 +717,19 @@ mod tests {
683717
.map(|uri| Uri::try_from(*uri).unwrap())
684718
.collect();
685719

686-
assert_eq!(uris[0].resource(), "/bar/baz?query#fragment");
687-
assert_eq!(uris[1].resource(), "/C:/Users/User/Pictures/screenshot.png");
688-
assert_eq!(uris[2].resource(), "/wiki/Hypertext_Transfer_Protocol");
689-
assert_eq!(uris[3].resource(), "John.Doe@example.com");
690-
assert_eq!(uris[4].resource(), "/");
720+
const RESULT: [&str; 7] = [
721+
"/bar/baz?query#fragment",
722+
"/C:/Users/User/Pictures/screenshot.png",
723+
"/wiki/Hypertext_Transfer_Protocol",
724+
"John.Doe@example.com",
725+
"/",
726+
"/?query=val",
727+
"/#fragment"
728+
];
729+
730+
for i in 0..RESULT.len() {
731+
assert_eq!(uris[i].resource(), RESULT[i]);
732+
}
691733
}
692734

693735
#[test]

0 commit comments

Comments
 (0)