From 678a3d34bf04992662caa765340ed22a353eebd7 Mon Sep 17 00:00:00 2001 From: Tunglies Date: Thu, 14 Mar 2024 12:42:22 +0800 Subject: [PATCH] Fix httpx is not encoding with symbol '%s' (#3140) Add parsing symbol '%s' test --- httpx/_urlparse.py | 22 ++++++++++++++++------ tests/models/test_url.py | 2 ++ 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/httpx/_urlparse.py b/httpx/_urlparse.py index 232269ee4d..e3e012f8c4 100644 --- a/httpx/_urlparse.py +++ b/httpx/_urlparse.py @@ -424,13 +424,23 @@ def is_safe(string: str, safe: str = "/") -> bool: """ Determine if a given string is already quote-safe. """ - NON_ESCAPED_CHARS = UNRESERVED_CHARACTERS + safe + "%" - - # All characters must already be non-escaping or '%' - for char in string: - if char not in NON_ESCAPED_CHARS: + NON_ESCAPED_CHARS = UNRESERVED_CHARACTERS + safe + i = 0 + while i < len(string): + char = string[i] + if char in NON_ESCAPED_CHARS: + i += 1 + continue + # Check if the character is a start of a valid percent-encoded sequence + elif ( + char == "%" + and i + 2 < len(string) + and string[i + 1 : i + 3].isalnum() + and len(string[i + 1 : i + 3]) == 2 + ): + i += 3 + else: return False - return True diff --git a/tests/models/test_url.py b/tests/models/test_url.py index 79e1605a5a..a81dbc6248 100644 --- a/tests/models/test_url.py +++ b/tests/models/test_url.py @@ -284,6 +284,8 @@ def test_url_leading_dot_prefix_on_relative_url(): def test_param_requires_encoding(): url = httpx.URL("http://webservice", params={"u": "with spaces"}) assert str(url) == "http://webservice?u=with%20spaces" + url = httpx.URL("http://webservice", params={"u": "%"}) + assert str(url) == "http://webservice?u=%25" def test_param_does_not_require_encoding():