1#![allow(unused_results)]
18
19use reqwest::Url;
20
21#[inline]
22pub fn is_root(url: &Url) -> bool {
23 !url.path_segments().unwrap().any(|x| !x.is_empty())
24}
25
26#[inline]
27pub fn extend<I>(mut url: Url, segments: I) -> Url
28where
29 I: IntoIterator,
30 I::Item: AsRef<str>,
31{
32 url.path_segments_mut()
33 .unwrap()
34 .pop_if_empty()
35 .extend(segments);
36 url
37}
38
39#[inline]
40pub fn pop(mut url: Url) -> Url {
41 url.path_segments_mut()
42 .expect("Invalid URL")
43 .pop_if_empty()
44 .pop()
45 .pop_if_empty()
46 .push("");
47 url
48}
49
50pub fn merge(dest: &mut Url, src: &Url) {
52 dest.set_scheme(src.scheme()).unwrap();
54 dest.set_host(src.host_str()).unwrap();
55 dest.set_port(src.port()).unwrap();
56 let existing: Vec<String> = dest
57 .path_segments()
58 .unwrap()
59 .map(|segment| {
60 percent_encoding::percent_decode_str(segment)
61 .decode_utf8_lossy()
62 .into_owned()
63 })
64 .collect();
65 dest.path_segments_mut()
66 .unwrap()
67 .clear()
68 .extend(src.path_segments().unwrap())
69 .pop_if_empty()
70 .extend(existing);
71}
72
73#[cfg(test)]
74mod test {
75 use reqwest::Url;
76
77 use super::*;
78
79 #[test]
80 fn test_is_root() {
81 assert!(is_root(&Url::parse("https://example.com").unwrap()));
82 assert!(is_root(&Url::parse("https://example.com/").unwrap()));
83 }
84
85 #[test]
86 fn test_is_not_root() {
87 assert!(!is_root(&Url::parse("https://example.com/v1/").unwrap()));
88 assert!(!is_root(
89 &Url::parse("https://example.com/v2/project_id").unwrap()
90 ));
91 }
92
93 #[test]
94 fn test_pop() {
95 assert_eq!(
96 pop(Url::parse("https://example.com/v1").unwrap()).as_str(),
97 "https://example.com/"
98 );
99 assert_eq!(
100 pop(Url::parse("https://example.com/v1/").unwrap()).as_str(),
101 "https://example.com/"
102 );
103 assert_eq!(
104 pop(Url::parse("https://example.com/v1/foobar").unwrap()).as_str(),
105 "https://example.com/v1/"
106 );
107 assert_eq!(
108 pop(Url::parse("https://example.com/v1/foobar/").unwrap()).as_str(),
109 "https://example.com/v1/"
110 );
111 }
112
113 #[test]
114 fn test_merge_host_only() {
115 let mut dest = Url::parse("http://compute").unwrap();
116 let src = Url::parse("https://example.com").unwrap();
117 merge(&mut dest, &src);
118 assert_eq!(dest.as_str(), "https://example.com/");
119 }
120
121 #[test]
122 fn test_merge_with_port() {
123 let mut dest = Url::parse("http://compute").unwrap();
124 let src = Url::parse("https://example.com:5050").unwrap();
125 merge(&mut dest, &src);
126 assert_eq!(dest.as_str(), "https://example.com:5050/");
127 }
128
129 #[test]
130 fn test_merge_existing_path() {
131 let mut dest = Url::parse("http://compute/path/1").unwrap();
132 let src = Url::parse("https://example.com").unwrap();
133 merge(&mut dest, &src);
134 assert_eq!(dest.as_str(), "https://example.com/path/1");
135 }
136
137 #[test]
138 fn test_merge_new_path() {
139 let mut dest = Url::parse("http://compute").unwrap();
140 let src = Url::parse("https://example.com/compute").unwrap();
141 merge(&mut dest, &src);
142 assert_eq!(dest.as_str(), "https://example.com/compute/");
143 }
144
145 #[test]
146 fn test_merge_combine_args() {
147 let mut dest = Url::parse("http://compute/?answer=42").unwrap();
148 let src = Url::parse("https://example.com").unwrap();
149 merge(&mut dest, &src);
150 assert_eq!(dest.as_str(), "https://example.com/?answer=42");
151 }
152
153 #[test]
154 fn test_merge_combine_path() {
155 let mut dest = Url::parse("http://compute/path/1").unwrap();
156 let src = Url::parse("https://example.com/compute").unwrap();
157 merge(&mut dest, &src);
158 assert_eq!(dest.as_str(), "https://example.com/compute/path/1");
159 }
160
161 #[test]
162 fn test_merge_combine_everything() {
163 let mut dest = Url::parse("http://compute/path/1/?foo=bar,answer=42").unwrap();
164 let src = Url::parse("https://example.com:5050/compute/").unwrap();
165 merge(&mut dest, &src);
166 assert_eq!(
167 dest.as_str(),
168 "https://example.com:5050/compute/path/1/?foo=bar,answer=42"
169 );
170 }
171
172 #[test]
173 fn test_merge_with_percent_encoded_segments() {
174 let mut dest = Url::parse("http://compute/path%2Fto/foo%20bar").unwrap();
175 let src = Url::parse("https://example.com:5050/compute/").unwrap();
176 merge(&mut dest, &src);
177 assert_eq!(
178 dest.as_str(),
179 "https://example.com:5050/compute/path%2Fto/foo%20bar"
180 );
181 }
182}