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