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