anyxml_uri/
lib.rs

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