web_url/parse/pre_path/
pre_path.rs1use address::IPAddress;
2
3use crate::parse::pre_path::parse_scheme_len;
4use crate::parse::pre_path::{parse_host, parse_ip_and_validate_domain, parse_port};
5use crate::parse::Error;
6
7#[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug)]
9pub struct PrePath {
10 pub scheme_len: usize,
11 pub host_len: usize,
12 pub ip: Option<IPAddress>,
13 pub port: Option<u16>,
14 pub port_len: usize,
15}
16
17impl PrePath {
18 pub fn len(&self) -> usize {
22 self.scheme_len + 3 + self.host_len + self.port_len
23 }
24
25 pub fn is_empty(&self) -> bool {
27 false
28 }
29}
30
31impl PrePath {
32 pub unsafe fn make_lowercase(&self, url: &mut str) {
40 url[..self.len()]
41 .as_bytes_mut()
42 .iter_mut()
43 .for_each(|c| *c = c.to_ascii_lowercase())
44 }
45}
46
47pub fn parse_pre_path(url: &str) -> Result<PrePath, Error> {
53 let (scheme_len, after_scheme) = parse_scheme_len(url)?;
54 let (host_str, after_host) = parse_host(after_scheme);
55 let ip: Option<IPAddress> = parse_ip_and_validate_domain(host_str)?;
56 let (port, after_port) = parse_port(after_host)?;
57 let port_len: usize = after_host.len() - after_port.len();
58 let pre_path: PrePath = PrePath {
59 scheme_len,
60 host_len: host_str.len(),
61 ip,
62 port,
63 port_len,
64 };
65 Ok(pre_path)
66}
67
68#[cfg(test)]
69mod tests {
70 use address::{IPv4Address, IPv6Address};
71
72 use crate::parse::pre_path::{parse_pre_path, PrePath};
73 use crate::parse::Error;
74 use crate::parse::Error::{InvalidHost, InvalidScheme};
75
76 #[test]
77 fn fn_parse_pre_path() {
78 let test_cases: &[(&str, Result<PrePath, Error>)] = &[
79 ("scheme:/", Err(InvalidScheme)),
80 ("!://", Err(InvalidScheme)),
81 ("scheme://", Err(InvalidHost)),
82 (
83 "scheme://host",
84 Ok(PrePath {
85 scheme_len: 6,
86 host_len: 4,
87 ip: None,
88 port: None,
89 port_len: 0,
90 }),
91 ),
92 (
93 "scheme://127.0.0.1",
94 Ok(PrePath {
95 scheme_len: 6,
96 host_len: 9,
97 ip: Some(IPv4Address::LOCALHOST.to_ip()),
98 port: None,
99 port_len: 0,
100 }),
101 ),
102 ("scheme://::1", Err(InvalidHost)),
103 (
104 "scheme://[::1]",
105 Ok(PrePath {
106 scheme_len: 6,
107 host_len: 5,
108 ip: Some(IPv6Address::LOCALHOST.to_ip()),
109 port: None,
110 port_len: 0,
111 }),
112 ),
113 (
114 "scheme://[::1]:80",
115 Ok(PrePath {
116 scheme_len: 6,
117 host_len: 5,
118 ip: Some(IPv6Address::LOCALHOST.to_ip()),
119 port: Some(80),
120 port_len: 3,
121 }),
122 ),
123 (
124 "scheme://[::1]:80/the/path",
125 Ok(PrePath {
126 scheme_len: 6,
127 host_len: 5,
128 ip: Some(IPv6Address::LOCALHOST.to_ip()),
129 port: Some(80),
130 port_len: 3,
131 }),
132 ),
133 ];
134 for (input, expected) in test_cases {
135 let result: Result<PrePath, Error> = parse_pre_path(input);
136 assert_eq!(result, *expected, "input={}", input);
137 }
138 }
139}