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