Skip to main content

anyxml_uri/
lib.rs

1pub mod rfc2396;
2pub mod uri;
3
4/// Parse errors.
5#[derive(Debug, Clone, Copy)]
6pub enum ParseRIError {
7    InvalidAuthority,
8    InvalidPathAbsolute,
9    InvalidSegment,
10    InvalidSegmentNzNc,
11    InvalidPChar,
12    InvalidScheme,
13    InvalidSchemeSeparator,
14    InvalidIPLiteral,
15    InvalidIPvFuture,
16    InvalidIPv6address,
17    InvalidH16,
18    InvalidLS32,
19    InvalidIPv4address,
20    InvalidDecOctet,
21    InvalidPctEncoded,
22    NotTermination,
23    Unsupported,
24    Unknown,
25}
26
27impl std::fmt::Display for ParseRIError {
28    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
29        write!(f, "{self:?}")
30    }
31}
32
33impl std::error::Error for ParseRIError {}
34
35#[cfg(test)]
36mod tests {
37    use crate::uri::URIString;
38
39    /// [1.1.2.  Examples](https://datatracker.ietf.org/doc/html/rfc3986#section-1.1.2)
40    /// [3.  Syntax Components](https://datatracker.ietf.org/doc/html/rfc3986#section-3)
41    /// [iri-string crate](https://docs.rs/iri-string/latest/iri_string/index.html)
42    #[test]
43    fn uri_parse_tests() {
44        let uri = URIString::parse(r#"ftp://ftp.is.co.za/rfc/rfc1808.txt"#).unwrap();
45        assert_eq!(uri.scheme().unwrap(), "ftp");
46        assert_eq!(uri.authority().unwrap(), "ftp.is.co.za");
47        assert!(uri.userinfo().is_none());
48        assert_eq!(uri.host().unwrap(), "ftp.is.co.za");
49        assert!(uri.port().is_none());
50        assert_eq!(uri.path(), "/rfc/rfc1808.txt");
51        assert!(uri.query().is_none());
52        assert!(uri.fragment().is_none());
53
54        let uri = URIString::parse(r#"http://www.ietf.org/rfc/rfc2396.txt"#).unwrap();
55        assert_eq!(uri.scheme().unwrap(), "http");
56        assert_eq!(uri.authority().unwrap(), "www.ietf.org");
57        assert!(uri.userinfo().is_none());
58        assert_eq!(uri.host().unwrap(), "www.ietf.org");
59        assert!(uri.port().is_none());
60        assert_eq!(uri.path(), "/rfc/rfc2396.txt");
61        assert!(uri.query().is_none());
62        assert!(uri.fragment().is_none());
63
64        let uri = URIString::parse(r#"ldap://[2001:db8::7]/c=GB?objectClass?one"#).unwrap();
65        assert_eq!(uri.scheme().unwrap(), "ldap");
66        assert_eq!(uri.authority().unwrap(), "[2001:db8::7]");
67        assert!(uri.userinfo().is_none());
68        assert_eq!(uri.host().unwrap(), "[2001:db8::7]");
69        assert!(uri.port().is_none());
70        assert_eq!(uri.path(), "/c=GB");
71        assert_eq!(uri.query().unwrap(), "objectClass?one");
72        assert!(uri.fragment().is_none());
73
74        let uri = URIString::parse(r#"mailto:John.Doe@example.com"#).unwrap();
75        assert_eq!(uri.scheme().unwrap(), "mailto");
76        assert!(uri.authority().is_none());
77        assert!(uri.userinfo().is_none());
78        assert!(uri.host().is_none());
79        assert!(uri.port().is_none());
80        assert_eq!(uri.path(), "John.Doe@example.com");
81        assert!(uri.query().is_none());
82        assert!(uri.fragment().is_none());
83
84        let uri = URIString::parse(r#"news:comp.infosystems.www.servers.unix"#).unwrap();
85        assert_eq!(uri.scheme().unwrap(), "news");
86        assert!(uri.authority().is_none());
87        assert!(uri.userinfo().is_none());
88        assert!(uri.host().is_none());
89        assert!(uri.port().is_none());
90        assert_eq!(uri.path(), "comp.infosystems.www.servers.unix");
91        assert!(uri.query().is_none());
92        assert!(uri.fragment().is_none());
93
94        let uri = URIString::parse(r#"tel:+1-816-555-1212"#).unwrap();
95        assert_eq!(uri.scheme().unwrap(), "tel");
96        assert!(uri.authority().is_none());
97        assert!(uri.userinfo().is_none());
98        assert!(uri.host().is_none());
99        assert!(uri.port().is_none());
100        assert_eq!(uri.path(), "+1-816-555-1212");
101        assert!(uri.query().is_none());
102        assert!(uri.fragment().is_none());
103
104        let uri = URIString::parse(r#"telnet://192.0.2.16:80/"#).unwrap();
105        assert_eq!(uri.scheme().unwrap(), "telnet");
106        assert_eq!(uri.authority().unwrap(), "192.0.2.16:80");
107        assert!(uri.userinfo().is_none());
108        assert_eq!(uri.host().unwrap(), "192.0.2.16");
109        assert_eq!(uri.port().unwrap(), "80");
110        assert_eq!(uri.path(), "/");
111        assert!(uri.query().is_none());
112        assert!(uri.fragment().is_none());
113
114        let uri =
115            URIString::parse(r#"urn:oasis:names:specification:docbook:dtd:xml:4.1.2"#).unwrap();
116        assert_eq!(uri.scheme().unwrap(), "urn");
117        assert!(uri.authority().is_none());
118        assert!(uri.userinfo().is_none());
119        assert!(uri.host().is_none());
120        assert!(uri.port().is_none());
121        assert_eq!(
122            uri.path(),
123            "oasis:names:specification:docbook:dtd:xml:4.1.2"
124        );
125        assert!(uri.query().is_none());
126        assert!(uri.fragment().is_none());
127
128        let uri =
129            URIString::parse(r#"foo://example.com:8042/over/there?name=ferret#nose"#).unwrap();
130        assert_eq!(uri.scheme().unwrap(), "foo");
131        assert_eq!(uri.authority().unwrap(), "example.com:8042");
132        assert!(uri.userinfo().is_none());
133        assert_eq!(uri.host().unwrap(), "example.com");
134        assert_eq!(uri.port().unwrap(), "8042");
135        assert_eq!(uri.path(), "/over/there");
136        assert_eq!(uri.query().unwrap(), "name=ferret");
137        assert_eq!(uri.fragment().unwrap(), "nose");
138
139        // [iri-string crate](https://docs.rs/iri-string/latest/iri_string/index.html)
140        let uri = URIString::parse(r#"foo:"#).unwrap();
141        assert_eq!(uri.scheme().unwrap(), "foo");
142        assert!(uri.authority().is_none());
143        assert!(uri.userinfo().is_none());
144        assert!(uri.host().is_none());
145        assert!(uri.port().is_none());
146        assert_eq!(uri.path(), "");
147        assert!(uri.query().is_none());
148        assert!(uri.fragment().is_none());
149
150        let uri = URIString::parse(r#"foo:/"#).unwrap();
151        assert_eq!(uri.scheme().unwrap(), "foo");
152        assert!(uri.authority().is_none());
153        assert!(uri.userinfo().is_none());
154        assert!(uri.host().is_none());
155        assert!(uri.port().is_none());
156        assert_eq!(uri.path(), "/");
157        assert!(uri.query().is_none());
158        assert!(uri.fragment().is_none());
159
160        let uri = URIString::parse(r#"foo://"#).unwrap();
161        assert_eq!(uri.scheme().unwrap(), "foo");
162        assert_eq!(uri.authority().unwrap(), "");
163        assert!(uri.userinfo().is_none());
164        assert_eq!(uri.host().unwrap(), "");
165        assert!(uri.port().is_none());
166        assert_eq!(uri.path(), "");
167        assert!(uri.query().is_none());
168        assert!(uri.fragment().is_none());
169
170        let uri = URIString::parse(r#"foo:///"#).unwrap();
171        assert_eq!(uri.scheme().unwrap(), "foo");
172        assert_eq!(uri.authority().unwrap(), "");
173        assert!(uri.userinfo().is_none());
174        assert_eq!(uri.host().unwrap(), "");
175        assert!(uri.port().is_none());
176        assert_eq!(uri.path(), "/");
177        assert!(uri.query().is_none());
178        assert!(uri.fragment().is_none());
179
180        let uri = URIString::parse(r#"foo:////"#).unwrap();
181        assert_eq!(uri.scheme().unwrap(), "foo");
182        assert_eq!(uri.authority().unwrap(), "");
183        assert!(uri.userinfo().is_none());
184        assert_eq!(uri.host().unwrap(), "");
185        assert!(uri.port().is_none());
186        assert_eq!(uri.path(), "//");
187        assert!(uri.query().is_none());
188        assert!(uri.fragment().is_none());
189    }
190
191    /// [5.4.  Reference Resolution Examples](https://datatracker.ietf.org/doc/html/rfc3986#section-5.4)
192    #[test]
193    fn uri_resolve_tests() {
194        let base = URIString::parse(r#"http://a/b/c/d;p?q"#).unwrap();
195        assert!(base.is_absolute());
196
197        // 5.4.1.  Normal Examples
198        let rel = URIString::parse("g:h").unwrap();
199        assert_eq!(base.resolve(&rel).as_escaped_str(), "g:h");
200        let rel = URIString::parse("g").unwrap();
201        assert_eq!(base.resolve(&rel).as_escaped_str(), "http://a/b/c/g");
202        let rel = URIString::parse("./g").unwrap();
203        assert_eq!(base.resolve(&rel).as_escaped_str(), "http://a/b/c/g");
204        let rel = URIString::parse("g/").unwrap();
205        assert_eq!(base.resolve(&rel).as_escaped_str(), "http://a/b/c/g/");
206        let rel = URIString::parse("/g").unwrap();
207        assert_eq!(base.resolve(&rel).as_escaped_str(), "http://a/g");
208        let rel = URIString::parse("//g").unwrap();
209        assert_eq!(base.resolve(&rel).as_escaped_str(), "http://g");
210        let rel = URIString::parse("?y").unwrap();
211        assert_eq!(base.resolve(&rel).as_escaped_str(), "http://a/b/c/d;p?y");
212        let rel = URIString::parse("g?y").unwrap();
213        assert_eq!(base.resolve(&rel).as_escaped_str(), "http://a/b/c/g?y");
214        let rel = URIString::parse("#s").unwrap();
215        assert_eq!(base.resolve(&rel).as_escaped_str(), "http://a/b/c/d;p?q#s");
216        let rel = URIString::parse("g#s").unwrap();
217        assert_eq!(base.resolve(&rel).as_escaped_str(), "http://a/b/c/g#s");
218        let rel = URIString::parse("g?y#s").unwrap();
219        assert_eq!(base.resolve(&rel).as_escaped_str(), "http://a/b/c/g?y#s");
220        let rel = URIString::parse(";x").unwrap();
221        assert_eq!(base.resolve(&rel).as_escaped_str(), "http://a/b/c/;x");
222        let rel = URIString::parse("g;x").unwrap();
223        assert_eq!(base.resolve(&rel).as_escaped_str(), "http://a/b/c/g;x");
224        let rel = URIString::parse("g;x?y#s").unwrap();
225        assert_eq!(base.resolve(&rel).as_escaped_str(), "http://a/b/c/g;x?y#s");
226        let rel = URIString::parse("").unwrap();
227        assert_eq!(base.resolve(&rel).as_escaped_str(), "http://a/b/c/d;p?q");
228        let rel = URIString::parse(".").unwrap();
229        assert_eq!(base.resolve(&rel).as_escaped_str(), "http://a/b/c/");
230        let rel = URIString::parse("./").unwrap();
231        assert_eq!(base.resolve(&rel).as_escaped_str(), "http://a/b/c/");
232        let rel = URIString::parse("..").unwrap();
233        assert_eq!(base.resolve(&rel).as_escaped_str(), "http://a/b/");
234        let rel = URIString::parse("../").unwrap();
235        assert_eq!(base.resolve(&rel).as_escaped_str(), "http://a/b/");
236        let rel = URIString::parse("../g").unwrap();
237        assert_eq!(base.resolve(&rel).as_escaped_str(), "http://a/b/g");
238        let rel = URIString::parse("../..").unwrap();
239        assert_eq!(base.resolve(&rel).as_escaped_str(), "http://a/");
240        let rel = URIString::parse("../../").unwrap();
241        assert_eq!(base.resolve(&rel).as_escaped_str(), "http://a/");
242        let rel = URIString::parse("../../g").unwrap();
243        assert_eq!(base.resolve(&rel).as_escaped_str(), "http://a/g");
244
245        // [5.4.2.  Abnormal Examples](https://datatracker.ietf.org/doc/html/rfc3986#section-5.4.2)
246        let rel = URIString::parse("../../../g").unwrap();
247        assert_eq!(base.resolve(&rel).as_escaped_str(), "http://a/g");
248        let rel = URIString::parse("../../../../g").unwrap();
249        assert_eq!(base.resolve(&rel).as_escaped_str(), "http://a/g");
250        let rel = URIString::parse("/./g").unwrap();
251        assert_eq!(base.resolve(&rel).as_escaped_str(), "http://a/g");
252        let rel = URIString::parse("/../g").unwrap();
253        assert_eq!(base.resolve(&rel).as_escaped_str(), "http://a/g");
254        let rel = URIString::parse("g.").unwrap();
255        assert_eq!(base.resolve(&rel).as_escaped_str(), "http://a/b/c/g.");
256        let rel = URIString::parse(".g").unwrap();
257        assert_eq!(base.resolve(&rel).as_escaped_str(), "http://a/b/c/.g");
258        let rel = URIString::parse("g..").unwrap();
259        assert_eq!(base.resolve(&rel).as_escaped_str(), "http://a/b/c/g..");
260        let rel = URIString::parse("..g").unwrap();
261        assert_eq!(base.resolve(&rel).as_escaped_str(), "http://a/b/c/..g");
262        let rel = URIString::parse("./../g").unwrap();
263        assert_eq!(base.resolve(&rel).as_escaped_str(), "http://a/b/g");
264        let rel = URIString::parse("./g/.").unwrap();
265        assert_eq!(base.resolve(&rel).as_escaped_str(), "http://a/b/c/g/");
266        let rel = URIString::parse("g/./h").unwrap();
267        assert_eq!(base.resolve(&rel).as_escaped_str(), "http://a/b/c/g/h");
268        let rel = URIString::parse("g/../h").unwrap();
269        assert_eq!(base.resolve(&rel).as_escaped_str(), "http://a/b/c/h");
270        let rel = URIString::parse("g;x=1/./y").unwrap();
271        assert_eq!(base.resolve(&rel).as_escaped_str(), "http://a/b/c/g;x=1/y");
272        let rel = URIString::parse("g;x=1/../y").unwrap();
273        assert_eq!(base.resolve(&rel).as_escaped_str(), "http://a/b/c/y");
274        let rel = URIString::parse("g?y/./x").unwrap();
275        assert_eq!(base.resolve(&rel).as_escaped_str(), "http://a/b/c/g?y/./x");
276        let rel = URIString::parse("g?y/../x").unwrap();
277        assert_eq!(base.resolve(&rel).as_escaped_str(), "http://a/b/c/g?y/../x");
278        let rel = URIString::parse("g#s/./x").unwrap();
279        assert_eq!(base.resolve(&rel).as_escaped_str(), "http://a/b/c/g#s/./x");
280        let rel = URIString::parse("g#s/../x").unwrap();
281        assert_eq!(base.resolve(&rel).as_escaped_str(), "http://a/b/c/g#s/../x");
282
283        // [Testing XML Base Conformance](https://www.w3.org/XML/2006/12/xmlbase-testing.html)
284        assert_eq!(
285            URIString::parse("http://www.example.org/one/two")
286                .unwrap()
287                .resolve(&URIString::parse("").unwrap())
288                .as_escaped_str(),
289            "http://www.example.org/one/two"
290        );
291        assert_eq!(
292            URIString::parse("http://www.example.org/one/two#frag")
293                .unwrap()
294                .resolve(&URIString::parse("").unwrap())
295                .as_escaped_str(),
296            "http://www.example.org/one/two"
297        );
298    }
299
300    #[cfg(target_family = "windows")]
301    #[test]
302    fn windows_path_test() {
303        assert_eq!(
304            URIString::parse_file_path("C:\\Windows\\System32\\")
305                .unwrap()
306                .as_escaped_str(),
307            "file:C:/Windows/System32/"
308        );
309        assert_eq!(
310            URIString::parse_file_path("\\\\localhost\\share\\")
311                .unwrap()
312                .as_escaped_str(),
313            "file://localhost/share/"
314        );
315
316        let test = URIString::parse_file_path("resources\\test.xml").unwrap();
317        assert_eq!(test.as_unescaped_str().unwrap(), "resources/test.xml");
318
319        let base = URIString::parse_file_path("C:\\Users\\someuser\\Document\\").unwrap();
320        assert_eq!(
321            base.as_unescaped_str().unwrap(),
322            "file:C:/Users/someuser/Document/"
323        );
324
325        let resolved = base.resolve(&test);
326        assert_eq!(
327            resolved.as_unescaped_str().unwrap(),
328            "file:C:/Users/someuser/Document/resources/test.xml"
329        );
330    }
331}