anyxml_uri/
lib.rs

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