# If a URL includes any ASCII control characters including \t, \r, \n,
# then treat it as invalid.
if any(char.isascii() and not char.isprintable() for char in url):
- raise InvalidURL("Invalid non-printable ASCII character in URL")
+ char = next(char for char in url if char.isascii() and not char.isprintable())
+ idx = url.find(char)
+ error = (
+ f"Invalid non-printable ASCII character in URL, {char!r} at position {idx}."
+ )
+ raise InvalidURL(error)
# Some keyword arguments require special handling.
# ------------------------------------------------
# If a component includes any ASCII control characters including \t, \r, \n,
# then treat it as invalid.
if any(char.isascii() and not char.isprintable() for char in value):
- raise InvalidURL(
- f"Invalid non-printable ASCII character in URL component '{key}'"
+ char = next(
+ char for char in value if char.isascii() and not char.isprintable()
+ )
+ idx = value.find(char)
+ error = (
+ f"Invalid non-printable ASCII character in URL {key} component, "
+ f"{char!r} at position {idx}."
)
+ raise InvalidURL(error)
# Ensure that keyword arguments match as a valid regex.
if not COMPONENT_REGEX[key].fullmatch(value):
def test_url_non_printing_character_in_url():
with pytest.raises(httpx.InvalidURL) as exc:
httpx.URL("https://www.example.com/\n")
- assert str(exc.value) == "Invalid non-printable ASCII character in URL"
+ assert str(exc.value) == (
+ "Invalid non-printable ASCII character in URL, '\\n' at position 24."
+ )
def test_url_non_printing_character_in_component():
with pytest.raises(httpx.InvalidURL) as exc:
httpx.URL("https://www.example.com", path="/\n")
- assert (
- str(exc.value)
- == "Invalid non-printable ASCII character in URL component 'path'"
+ assert str(exc.value) == (
+ "Invalid non-printable ASCII character in URL path component, "
+ "'\\n' at position 1."
)