Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork 1.3k
Cleanup URL percent-encoding behavior.#2990
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Uh oh!
There was an error while loading. Please reload this page.
Changes from all commits
9c669b76cc7555b7d4258412a880a1b4afcde9968a7bdf22776ec6ebdd7b6570d8cc4be3532aa84f633853d15f1File filter
Filter by extension
Conversations
Uh oh!
There was an error while loading. Please reload this page.
Jump to
Uh oh!
There was an error while loading. Please reload this page.
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -260,10 +260,8 @@ def urlparse(url: str = "", **kwargs: typing.Optional[str]) -> ParseResult: | ||
| # For 'path' we need to drop ? and # from the GEN_DELIMS set. | ||
| parsed_path: str = quote(path, safe=SUB_DELIMS + ":/[]@") | ||
| # For 'query' we need to drop '#' from the GEN_DELIMS set. | ||
| # We also exclude '/' because it is more robust to replace it with a percent | ||
| # encoding despite it not being a requirement of the spec. | ||
| parsed_query: typing.Optional[str] = ( | ||
| None if query is None else quote(query, safe=SUB_DELIMS + ":?[]@") | ||
| None if query is None else quote(query, safe=SUB_DELIMS + ":/?[]@") | ||
| ) | ||
| # For 'fragment' we can include all of the GEN_DELIMS set. | ||
| parsed_fragment: typing.Optional[str] = ( | ||
| @@ -432,13 +430,12 @@ def is_safe(string: str, safe: str = "/") -> bool: | ||
| if char not in NON_ESCAPED_CHARS: | ||
| return False | ||
| # Any '%' characters must be valid '%xx' escape sequences. | ||
| return string.count("%") == len(PERCENT_ENCODED_REGEX.findall(string)) | ||
| return True | ||
| def quote(string: str, safe: str = "/") -> str: | ||
| def percent_encoded(string: str, safe: str = "/") -> str: | ||
| """ | ||
| Use percent-encoding to quote a string if required. | ||
| Use percent-encoding to quote a string. | ||
| """ | ||
| if is_safe(string, safe=safe): | ||
| return string | ||
| @@ -449,6 +446,39 @@ def quote(string: str, safe: str = "/") -> str: | ||
| ) | ||
| def quote(string: str, safe: str = "/") -> str: | ||
Contributor There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I believe we should also add unit tests for these functions, rather than simply testing them with Contributor There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. IMO current approach is fine.
from https://github.com/encode/httpx/issues/2492#issue-1478857204 Contributor There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I agree testing the public API should be sufficient unless something private is particularly expensive to test via the public API. Contributor There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It's a matter of preference, but if we encounter regression in our | ||
| """ | ||
| Use percent-encoding to quote a string, omitting existing '%xx' escape sequences. | ||
| See: https://www.rfc-editor.org/rfc/rfc3986#section-2.1 | ||
| * `string`: The string to be percent-escaped. | ||
| * `safe`: A string containing characters that may be treated as safe, and do not | ||
| need to be escaped. Unreserved characters are always treated as safe. | ||
| See: https://www.rfc-editor.org/rfc/rfc3986#section-2.3 | ||
| """ | ||
lovelydinosaur marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. | ||
| parts = [] | ||
| current_position = 0 | ||
| for match in re.finditer(PERCENT_ENCODED_REGEX, string): | ||
| start_position, end_position = match.start(), match.end() | ||
| matched_text = match.group(0) | ||
| # Add any text up to the '%xx' escape sequence. | ||
| if start_position != current_position: | ||
| leading_text = string[current_position:start_position] | ||
| parts.append(percent_encoded(leading_text, safe=safe)) | ||
| # Add the '%xx' escape sequence. | ||
| parts.append(matched_text) | ||
| current_position = end_position | ||
| # Add any text after the final '%xx' escape sequence. | ||
| if current_position != len(string): | ||
| trailing_text = string[current_position:] | ||
| parts.append(percent_encoded(trailing_text, safe=safe)) | ||
| return "".join(parts) | ||
lovelydinosaur marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. | ||
| def urlencode(items: typing.List[typing.Tuple[str, str]]) -> str: | ||
| """ | ||
| We can use a much simpler version of the stdlib urlencode here because | ||
| @@ -464,4 +494,9 @@ def urlencode(items: typing.List[typing.Tuple[str, str]]) -> str: | ||
| - https://github.com/encode/httpx/issues/2721 | ||
| - https://docs.python.org/3/library/urllib.parse.html#urllib.parse.urlencode | ||
| """ | ||
| return "&".join([quote(k, safe="") + "=" + quote(v, safe="") for k, v in items]) | ||
| return "&".join( | ||
| [ | ||
| percent_encoded(k, safe="") + "=" + percent_encoded(v, safe="") | ||
| for k, v in items | ||
| ] | ||
| ) | ||
lovelydinosaur marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. | ||
Uh oh!
There was an error while loading. Please reload this page.