Skip to content

Commit 7c0cda1

Browse files
authored
Improve InvalidURL error message. (#3250)
1 parent beb501f commit 7c0cda1

File tree

3 files changed

+21
-7
lines changed

3 files changed

+21
-7
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
1212

1313
### Fixed
1414

15+
* Improved error messaging for `InvalidURL` exceptions. (#3250)
1516
* Fix `app` type signature in `ASGITransport`. (#3109)
1617

1718
## 0.27.0 (21st February, 2024)

httpx/_urlparse.py

+14-3
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,12 @@ def urlparse(url: str = "", **kwargs: str | None) -> ParseResult:
160160
# If a URL includes any ASCII control characters including \t, \r, \n,
161161
# then treat it as invalid.
162162
if any(char.isascii() and not char.isprintable() for char in url):
163-
raise InvalidURL("Invalid non-printable ASCII character in URL")
163+
char = next(char for char in url if char.isascii() and not char.isprintable())
164+
idx = url.find(char)
165+
error = (
166+
f"Invalid non-printable ASCII character in URL, {char!r} at position {idx}."
167+
)
168+
raise InvalidURL(error)
164169

165170
# Some keyword arguments require special handling.
166171
# ------------------------------------------------
@@ -205,9 +210,15 @@ def urlparse(url: str = "", **kwargs: str | None) -> ParseResult:
205210
# If a component includes any ASCII control characters including \t, \r, \n,
206211
# then treat it as invalid.
207212
if any(char.isascii() and not char.isprintable() for char in value):
208-
raise InvalidURL(
209-
f"Invalid non-printable ASCII character in URL component '{key}'"
213+
char = next(
214+
char for char in value if char.isascii() and not char.isprintable()
215+
)
216+
idx = value.find(char)
217+
error = (
218+
f"Invalid non-printable ASCII character in URL {key} component, "
219+
f"{char!r} at position {idx}."
210220
)
221+
raise InvalidURL(error)
211222

212223
# Ensure that keyword arguments match as a valid regex.
213224
if not COMPONENT_REGEX[key].fullmatch(value):

tests/models/test_url.py

+6-4
Original file line numberDiff line numberDiff line change
@@ -367,15 +367,17 @@ def test_url_excessively_long_component():
367367
def test_url_non_printing_character_in_url():
368368
with pytest.raises(httpx.InvalidURL) as exc:
369369
httpx.URL("https://www.example.com/\n")
370-
assert str(exc.value) == "Invalid non-printable ASCII character in URL"
370+
assert str(exc.value) == (
371+
"Invalid non-printable ASCII character in URL, '\\n' at position 24."
372+
)
371373

372374

373375
def test_url_non_printing_character_in_component():
374376
with pytest.raises(httpx.InvalidURL) as exc:
375377
httpx.URL("https://www.example.com", path="/\n")
376-
assert (
377-
str(exc.value)
378-
== "Invalid non-printable ASCII character in URL component 'path'"
378+
assert str(exc.value) == (
379+
"Invalid non-printable ASCII character in URL path component, "
380+
"'\\n' at position 1."
379381
)
380382

381383

0 commit comments

Comments
 (0)