1 | # -*- coding: utf-8 -*-
|
---|
2 | import pytest
|
---|
3 |
|
---|
4 | from rfc3986.exceptions import InvalidAuthority, ResolutionError
|
---|
5 | from rfc3986.misc import URI_MATCHER
|
---|
6 | from rfc3986.uri import URIReference
|
---|
7 |
|
---|
8 | from . import base
|
---|
9 |
|
---|
10 |
|
---|
11 | @pytest.fixture
|
---|
12 | def scheme_and_path_uri():
|
---|
13 | return "mailto:user@example.com"
|
---|
14 |
|
---|
15 |
|
---|
16 | class TestURIReferenceParsesURIs(base.BaseTestParsesURIs):
|
---|
17 | """Tests for URIReference handling of URIs."""
|
---|
18 |
|
---|
19 | test_class = URIReference
|
---|
20 |
|
---|
21 | def test_authority_info_raises_InvalidAuthority(self, invalid_uri):
|
---|
22 | """Test that an invalid IPv6 is caught by authority_info()."""
|
---|
23 | uri = URIReference.from_string(invalid_uri)
|
---|
24 | with pytest.raises(InvalidAuthority):
|
---|
25 | uri.authority_info()
|
---|
26 |
|
---|
27 | def test_attributes_catch_InvalidAuthority(self, invalid_uri):
|
---|
28 | """Test that an invalid IPv6 is caught by authority_info()."""
|
---|
29 | uri = URIReference.from_string(invalid_uri)
|
---|
30 | assert uri.host is None
|
---|
31 | assert uri.userinfo is None
|
---|
32 | assert uri.port is None
|
---|
33 |
|
---|
34 | def test_handles_absolute_path_uri(self, absolute_path_uri):
|
---|
35 | """Test that URIReference can handle a path-only URI."""
|
---|
36 | uri = URIReference.from_string(absolute_path_uri)
|
---|
37 | assert uri.path == absolute_path_uri
|
---|
38 | assert uri.authority_info() == {
|
---|
39 | "userinfo": None,
|
---|
40 | "host": None,
|
---|
41 | "port": None,
|
---|
42 | }
|
---|
43 |
|
---|
44 | def test_scheme_and_path_uri_is_valid(self, scheme_and_path_uri):
|
---|
45 | uri = self.test_class.from_string(scheme_and_path_uri)
|
---|
46 | assert uri.is_valid() is True
|
---|
47 |
|
---|
48 | def test_handles_scheme_and_path_uri(self, scheme_and_path_uri):
|
---|
49 | """Test that self.test_class can handle a `scheme:path` URI."""
|
---|
50 | uri = self.test_class.from_string(scheme_and_path_uri)
|
---|
51 | assert uri.path == "user@example.com"
|
---|
52 | assert uri.scheme == "mailto"
|
---|
53 | assert uri.query is None
|
---|
54 | assert uri.host is None
|
---|
55 | assert uri.port is None
|
---|
56 | assert uri.userinfo is None
|
---|
57 | assert uri.authority is None
|
---|
58 |
|
---|
59 | def test_parses_ipv6_to_path(self):
|
---|
60 | """Verify that we don't parse [ as a scheme."""
|
---|
61 | uri = self.test_class.from_string("[::1]")
|
---|
62 | assert uri.scheme is None
|
---|
63 | assert uri.authority is None
|
---|
64 | assert uri.path == "[::1]"
|
---|
65 |
|
---|
66 |
|
---|
67 | class TestURIValidation:
|
---|
68 | # Valid URI tests
|
---|
69 | def test_basic_uri_is_valid(self, basic_uri):
|
---|
70 | uri = URIReference.from_string(basic_uri)
|
---|
71 | assert uri.is_valid() is True
|
---|
72 |
|
---|
73 | def test_basic_uri_requiring_scheme(self, basic_uri):
|
---|
74 | uri = URIReference.from_string(basic_uri)
|
---|
75 | assert uri.is_valid(require_scheme=True) is True
|
---|
76 |
|
---|
77 | def test_basic_uri_requiring_authority(self, basic_uri):
|
---|
78 | uri = URIReference.from_string(basic_uri)
|
---|
79 | assert uri.is_valid(require_authority=True) is True
|
---|
80 |
|
---|
81 | def test_uri_with_everything_requiring_path(self, uri_with_everything):
|
---|
82 | uri = URIReference.from_string(uri_with_everything)
|
---|
83 | assert uri.is_valid(require_path=True) is True
|
---|
84 |
|
---|
85 | def test_uri_with_everything_requiring_query(self, uri_with_everything):
|
---|
86 | uri = URIReference.from_string(uri_with_everything)
|
---|
87 | assert uri.is_valid(require_query=True) is True
|
---|
88 |
|
---|
89 | def test_uri_with_everything_requiring_fragment(
|
---|
90 | self, uri_with_everything
|
---|
91 | ):
|
---|
92 | uri = URIReference.from_string(uri_with_everything)
|
---|
93 | assert uri.is_valid(require_fragment=True) is True
|
---|
94 |
|
---|
95 | def test_basic_uri_with_port_is_valid(self, basic_uri_with_port):
|
---|
96 | uri = URIReference.from_string(basic_uri_with_port)
|
---|
97 | assert uri.is_valid() is True
|
---|
98 |
|
---|
99 | def test_uri_with_port_and_userinfo_is_valid(
|
---|
100 | self, uri_with_port_and_userinfo
|
---|
101 | ):
|
---|
102 | uri = URIReference.from_string(uri_with_port_and_userinfo)
|
---|
103 | assert uri.is_valid() is True
|
---|
104 |
|
---|
105 | def test_basic_uri_with_path_is_valid(self, basic_uri_with_path):
|
---|
106 | uri = URIReference.from_string(basic_uri_with_path)
|
---|
107 | assert uri.is_valid() is True
|
---|
108 |
|
---|
109 | def test_uri_with_path_and_query_is_valid(self, uri_with_path_and_query):
|
---|
110 | uri = URIReference.from_string(uri_with_path_and_query)
|
---|
111 | assert uri.is_valid() is True
|
---|
112 |
|
---|
113 | def test_uri_with_everything_is_valid(self, uri_with_everything):
|
---|
114 | uri = URIReference.from_string(uri_with_everything)
|
---|
115 | assert uri.is_valid() is True
|
---|
116 |
|
---|
117 | def test_relative_uri_is_valid(self, relative_uri):
|
---|
118 | uri = URIReference.from_string(relative_uri)
|
---|
119 | assert uri.is_valid() is True
|
---|
120 |
|
---|
121 | def test_absolute_path_uri_is_valid(self, absolute_path_uri):
|
---|
122 | uri = URIReference.from_string(absolute_path_uri)
|
---|
123 | assert uri.is_valid() is True
|
---|
124 |
|
---|
125 | def test_scheme_and_path_uri_is_valid(self, scheme_and_path_uri):
|
---|
126 | uri = URIReference.from_string(scheme_and_path_uri)
|
---|
127 | assert uri.is_valid() is True
|
---|
128 |
|
---|
129 | # Invalid URI tests
|
---|
130 | def test_invalid_uri_is_not_valid(self, invalid_uri):
|
---|
131 | uri = URIReference.from_string(invalid_uri)
|
---|
132 | assert uri.is_valid() is False
|
---|
133 |
|
---|
134 | def test_invalid_scheme(self):
|
---|
135 | uri = URIReference("123", None, None, None, None)
|
---|
136 | assert uri.is_valid() is False
|
---|
137 |
|
---|
138 | def test_invalid_path(self):
|
---|
139 | uri = URIReference(None, None, "foo#bar", None, None)
|
---|
140 | assert uri.is_valid() is False
|
---|
141 |
|
---|
142 | def test_invalid_query_component(self):
|
---|
143 | uri = URIReference(None, None, None, "foo#bar", None)
|
---|
144 | assert uri.is_valid() is False
|
---|
145 |
|
---|
146 | def test_invalid_fragment_component(self):
|
---|
147 | uri = URIReference(None, None, None, None, "foo#bar")
|
---|
148 | assert uri.is_valid() is False
|
---|
149 |
|
---|
150 |
|
---|
151 | class TestURIReferenceUnsplits(base.BaseTestUnsplits):
|
---|
152 | test_class = URIReference
|
---|
153 |
|
---|
154 | def test_scheme_and_path_uri_unsplits(self, scheme_and_path_uri):
|
---|
155 | uri = self.test_class.from_string(scheme_and_path_uri)
|
---|
156 | assert uri.unsplit() == scheme_and_path_uri
|
---|
157 |
|
---|
158 |
|
---|
159 | class TestURIReferenceComparesToStrings:
|
---|
160 | def test_basic_uri(self, basic_uri):
|
---|
161 | uri = URIReference.from_string(basic_uri)
|
---|
162 | assert uri == basic_uri
|
---|
163 |
|
---|
164 | def test_basic_uri_with_port(self, basic_uri_with_port):
|
---|
165 | uri = URIReference.from_string(basic_uri_with_port)
|
---|
166 | assert uri == basic_uri_with_port
|
---|
167 |
|
---|
168 | def test_uri_with_port_and_userinfo(self, uri_with_port_and_userinfo):
|
---|
169 | uri = URIReference.from_string(uri_with_port_and_userinfo)
|
---|
170 | assert uri == uri_with_port_and_userinfo
|
---|
171 |
|
---|
172 | def test_basic_uri_with_path(self, basic_uri_with_path):
|
---|
173 | uri = URIReference.from_string(basic_uri_with_path)
|
---|
174 | assert uri == basic_uri_with_path
|
---|
175 |
|
---|
176 | def test_uri_with_path_and_query(self, uri_with_path_and_query):
|
---|
177 | uri = URIReference.from_string(uri_with_path_and_query)
|
---|
178 | assert uri == uri_with_path_and_query
|
---|
179 |
|
---|
180 | def test_uri_with_everything(self, uri_with_everything):
|
---|
181 | uri = URIReference.from_string(uri_with_everything)
|
---|
182 | assert uri == uri_with_everything
|
---|
183 |
|
---|
184 | def test_relative_uri(self, relative_uri):
|
---|
185 | uri = URIReference.from_string(relative_uri)
|
---|
186 | assert uri == relative_uri
|
---|
187 |
|
---|
188 | def test_absolute_path_uri(self, absolute_path_uri):
|
---|
189 | uri = URIReference.from_string(absolute_path_uri)
|
---|
190 | assert uri == absolute_path_uri
|
---|
191 |
|
---|
192 | def test_scheme_and_path_uri(self, scheme_and_path_uri):
|
---|
193 | uri = URIReference.from_string(scheme_and_path_uri)
|
---|
194 | assert uri == scheme_and_path_uri
|
---|
195 |
|
---|
196 |
|
---|
197 | class TestURIReferenceComparesToTuples:
|
---|
198 | def to_tuple(self, uri):
|
---|
199 | return URI_MATCHER.match(uri).groups()
|
---|
200 |
|
---|
201 | def test_basic_uri(self, basic_uri):
|
---|
202 | uri = URIReference.from_string(basic_uri)
|
---|
203 | assert uri == self.to_tuple(basic_uri)
|
---|
204 |
|
---|
205 | def test_basic_uri_with_port(self, basic_uri_with_port):
|
---|
206 | uri = URIReference.from_string(basic_uri_with_port)
|
---|
207 | assert uri == self.to_tuple(basic_uri_with_port)
|
---|
208 |
|
---|
209 | def test_uri_with_port_and_userinfo(self, uri_with_port_and_userinfo):
|
---|
210 | uri = URIReference.from_string(uri_with_port_and_userinfo)
|
---|
211 | assert uri == self.to_tuple(uri_with_port_and_userinfo)
|
---|
212 |
|
---|
213 | def test_basic_uri_with_path(self, basic_uri_with_path):
|
---|
214 | uri = URIReference.from_string(basic_uri_with_path)
|
---|
215 | assert uri == self.to_tuple(basic_uri_with_path)
|
---|
216 |
|
---|
217 | def test_uri_with_path_and_query(self, uri_with_path_and_query):
|
---|
218 | uri = URIReference.from_string(uri_with_path_and_query)
|
---|
219 | assert uri == self.to_tuple(uri_with_path_and_query)
|
---|
220 |
|
---|
221 | def test_uri_with_everything(self, uri_with_everything):
|
---|
222 | uri = URIReference.from_string(uri_with_everything)
|
---|
223 | assert uri == self.to_tuple(uri_with_everything)
|
---|
224 |
|
---|
225 | def test_relative_uri(self, relative_uri):
|
---|
226 | uri = URIReference.from_string(relative_uri)
|
---|
227 | assert uri == self.to_tuple(relative_uri)
|
---|
228 |
|
---|
229 | def test_absolute_path_uri(self, absolute_path_uri):
|
---|
230 | uri = URIReference.from_string(absolute_path_uri)
|
---|
231 | assert uri == self.to_tuple(absolute_path_uri)
|
---|
232 |
|
---|
233 | def test_scheme_and_path_uri(self, scheme_and_path_uri):
|
---|
234 | uri = URIReference.from_string(scheme_and_path_uri)
|
---|
235 | assert uri == self.to_tuple(scheme_and_path_uri)
|
---|
236 |
|
---|
237 |
|
---|
238 | def test_uri_comparison_raises_TypeError(basic_uri):
|
---|
239 | uri = URIReference.from_string(basic_uri)
|
---|
240 | with pytest.raises(TypeError):
|
---|
241 | uri == 1
|
---|
242 |
|
---|
243 |
|
---|
244 | class TestURIReferenceComparesToURIReferences:
|
---|
245 | def test_same_basic_uri(self, basic_uri):
|
---|
246 | uri = URIReference.from_string(basic_uri)
|
---|
247 | assert uri == uri
|
---|
248 |
|
---|
249 | def test_different_basic_uris(self, basic_uri, basic_uri_with_port):
|
---|
250 | uri = URIReference.from_string(basic_uri)
|
---|
251 | assert (uri == URIReference.from_string(basic_uri_with_port)) is False
|
---|
252 |
|
---|
253 |
|
---|
254 | class TestURIReferenceIsAbsolute:
|
---|
255 | def test_basic_uris_are_absolute(self, basic_uri):
|
---|
256 | uri = URIReference.from_string(basic_uri)
|
---|
257 | assert uri.is_absolute() is True
|
---|
258 |
|
---|
259 | def test_basic_uris_with_ports_are_absolute(self, basic_uri_with_port):
|
---|
260 | uri = URIReference.from_string(basic_uri_with_port)
|
---|
261 | assert uri.is_absolute() is True
|
---|
262 |
|
---|
263 | def test_basic_uris_with_paths_are_absolute(self, basic_uri_with_path):
|
---|
264 | uri = URIReference.from_string(basic_uri_with_path)
|
---|
265 | assert uri.is_absolute() is True
|
---|
266 |
|
---|
267 | def test_uri_with_everything_are_not_absolute(self, uri_with_everything):
|
---|
268 | uri = URIReference.from_string(uri_with_everything)
|
---|
269 | assert uri.is_absolute() is False
|
---|
270 |
|
---|
271 | def test_absolute_paths_are_not_absolute_uris(self, absolute_path_uri):
|
---|
272 | uri = URIReference.from_string(absolute_path_uri)
|
---|
273 | assert uri.is_absolute() is False
|
---|
274 |
|
---|
275 |
|
---|
276 | # @pytest.fixture(params=[
|
---|
277 | # basic_uri, basic_uri_with_port, basic_uri_with_path,
|
---|
278 | # scheme_and_path_uri, uri_with_path_and_query
|
---|
279 | # ])
|
---|
280 | # @pytest.fixture(params=[absolute_path_uri, relative_uri])
|
---|
281 |
|
---|
282 |
|
---|
283 | class TestURIReferencesResolve:
|
---|
284 | def test_with_basic_and_relative_uris(self, basic_uri, relative_uri):
|
---|
285 | R = URIReference.from_string(relative_uri)
|
---|
286 | B = URIReference.from_string(basic_uri)
|
---|
287 | T = R.resolve_with(basic_uri)
|
---|
288 | assert T.scheme == B.scheme
|
---|
289 | assert T.host == R.host
|
---|
290 | assert T.path == R.path
|
---|
291 |
|
---|
292 | def test_with_basic_and_absolute_path_uris(
|
---|
293 | self, basic_uri, absolute_path_uri
|
---|
294 | ):
|
---|
295 | R = URIReference.from_string(absolute_path_uri)
|
---|
296 | B = URIReference.from_string(basic_uri).normalize()
|
---|
297 | T = R.resolve_with(B)
|
---|
298 | assert T.scheme == B.scheme
|
---|
299 | assert T.host == B.host
|
---|
300 | assert T.path == R.path
|
---|
301 |
|
---|
302 | def test_with_basic_uri_and_relative_path(self, basic_uri):
|
---|
303 | R = URIReference.from_string("foo/bar/bogus")
|
---|
304 | B = URIReference.from_string(basic_uri).normalize()
|
---|
305 | T = R.resolve_with(B)
|
---|
306 | assert T.scheme == B.scheme
|
---|
307 | assert T.host == B.host
|
---|
308 | assert T.path == "/" + R.path
|
---|
309 |
|
---|
310 | def test_basic_uri_with_path_and_relative_path(self, basic_uri_with_path):
|
---|
311 | R = URIReference.from_string("foo/bar/bogus")
|
---|
312 | B = URIReference.from_string(basic_uri_with_path).normalize()
|
---|
313 | T = R.resolve_with(B)
|
---|
314 | assert T.scheme == B.scheme
|
---|
315 | assert T.host == B.host
|
---|
316 |
|
---|
317 | index = B.path.rfind("/")
|
---|
318 | assert T.path == B.path[:index] + "/" + R.path
|
---|
319 |
|
---|
320 | def test_uri_with_everything_raises_exception(self, uri_with_everything):
|
---|
321 | R = URIReference.from_string("foo/bar/bogus")
|
---|
322 | B = URIReference.from_string(uri_with_everything)
|
---|
323 | with pytest.raises(ResolutionError):
|
---|
324 | R.resolve_with(B)
|
---|
325 |
|
---|
326 | def test_basic_uri_resolves_itself(self, basic_uri):
|
---|
327 | R = URIReference.from_string(basic_uri)
|
---|
328 | B = URIReference.from_string(basic_uri)
|
---|
329 | T = R.resolve_with(B)
|
---|
330 | assert T == B
|
---|
331 |
|
---|
332 | def test_differing_schemes(self, basic_uri):
|
---|
333 | R = URIReference.from_string("https://example.com/path")
|
---|
334 | B = URIReference.from_string(basic_uri)
|
---|
335 | T = R.resolve_with(B)
|
---|
336 | assert T.scheme == R.scheme
|
---|
337 |
|
---|
338 | def test_resolve_pathless_fragment(self, basic_uri):
|
---|
339 | R = URIReference.from_string("#fragment")
|
---|
340 | B = URIReference.from_string(basic_uri)
|
---|
341 | T = R.resolve_with(B)
|
---|
342 | assert T.path is None
|
---|
343 | assert T.fragment == "fragment"
|
---|
344 |
|
---|
345 | def test_resolve_pathless_query(self, basic_uri):
|
---|
346 | R = URIReference.from_string("?query")
|
---|
347 | B = URIReference.from_string(basic_uri)
|
---|
348 | T = R.resolve_with(B)
|
---|
349 | assert T.path is None
|
---|
350 | assert T.query == "query"
|
---|
351 |
|
---|
352 |
|
---|
353 | def test_empty_querystrings_persist():
|
---|
354 | url = "https://httpbin.org/get?"
|
---|
355 | ref = URIReference.from_string(url)
|
---|
356 | assert ref.query == ""
|
---|
357 | assert ref.unsplit() == url
|
---|
358 |
|
---|
359 |
|
---|
360 | def test_wide_domain_bypass_check():
|
---|
361 | """Verify we properly parse/handle the authority.
|
---|
362 |
|
---|
363 | See also:
|
---|
364 | https://bugs.xdavidhu.me/google/2020/03/08/the-unexpected-google-wide-domain-check-bypass/
|
---|
365 | """
|
---|
366 | url = "https://user:pass@xdavidhu.me\\test.corp.google.com:8080/path/to/something?param=value#hash"
|
---|
367 | ref = URIReference.from_string(url)
|
---|
368 | assert ref.scheme == "https"
|
---|
369 | assert ref.host == "xdavidhu.me"
|
---|