"""
merge_url = URL(url)
if merge_url.is_relative_url:
- # We always ensure the base_url paths include the trailing '/',
- # and always strip any leading '/' from the merge URL.
- merge_url = merge_url.copy_with(raw_path=merge_url.raw_path.lstrip(b"/"))
- return self.base_url.join(merge_url)
+ # To merge URLs we always append to the base URL. To get this
+ # behaviour correct we always ensure the base URL ends in a '/'
+ # seperator, and strip any leading '/' from the merge URL.
+ #
+ # So, eg...
+ #
+ # >>> client = Client(base_url="https://www.example.com/subpath")
+ # >>> client.base_url
+ # URL('https://www.example.com/subpath/')
+ # >>> client.build_request("GET", "/path").url
+ # URL('https://www.example.com/subpath/path')
+ merge_raw_path = self.base_url.raw_path + merge_url.raw_path.lstrip(b"/")
+ return self.base_url.copy_with(raw_path=merge_raw_path)
return merge_url
def _merge_cookies(
assert url == "https://www.example.com/test/new/path"
"""
if self.is_relative_url:
- return URL(url)
+ # Workaround to handle relative URLs, which otherwise raise
+ # rfc3986.exceptions.ResolutionError when used as an argument
+ # in `.resolve_with`.
+ return (
+ self.copy_with(scheme="http", host="example.com")
+ .join(url)
+ .copy_with(scheme=None, host=None)
+ )
# We drop any fragment portion, because RFC 3986 strictly
# treats URLs with a fragment portion as not being absolute URLs.
assert request.url == "https://www.example.com/some/testing/123"
+def test_merge_relative_url_with_path_including_colon():
+ client = httpx.Client(base_url="https://www.example.com/some/path")
+ request = client.build_request("GET", "/testing:123")
+ assert request.url == "https://www.example.com/some/path/testing:123"
+
+
def test_merge_relative_url_with_encoded_slashes():
client = httpx.Client(base_url="https://www.example.com/")
request = client.build_request("GET", "/testing%2F123")
assert url.join("../../somewhere-else") == "https://example.org:123/somewhere-else"
+def test_relative_url_join():
+ url = httpx.URL("/path/to/somewhere")
+ assert url.join("/somewhere-else") == "/somewhere-else"
+ assert url.join("somewhere-else") == "/path/to/somewhere-else"
+ assert url.join("../somewhere-else") == "/path/somewhere-else"
+ assert url.join("../../somewhere-else") == "/somewhere-else"
+
+
def test_url_join_rfc3986():
"""
URL joining tests, as-per reference examples in RFC 3986.