Repository navigation
Python: Decode percent-encoded base64 data URI payloads #9664
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
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -38,6 +38,7 @@ | |
| get_args, | ||
| overload, | ||
| ) | ||
| from urllib.parse import unquote | ||
|
|
||
| from typing_extensions import Required, TypedDict | ||
|
|
||
|
|
@@ -116,6 +117,7 @@ def _parse_data_uri(uri: str) -> _ParsedDataUri: | |
| ``base64`` is the only encoding marker and is only valid once, as the last parameter; other | ||
| parameters such as ``charset=utf-8`` are metadata. Only the metadata before the first comma | ||
| is inspected, so a ``;base64,`` sequence inside the payload is never treated as a marker. | ||
| Payload URL escapes are decoded once before callers process the base64 data; literal ``+`` is preserved. | ||
|
|
||
| Raises: | ||
| ContentError: If the URI has no comma or carries an unsupported encoding marker. | ||
|
|
@@ -134,7 +136,7 @@ def _parse_data_uri(uri: str) -> _ParsedDataUri: | |
| return _ParsedDataUri( | ||
| media_type=parts[0][5:] or "text/plain", # Remove 'data:' | ||
| is_base64=bool(parameters) and parameters[-1] == "base64", | ||
| payload=payload, | ||
| payload=unquote(payload), | ||
|
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. This normalizes only
Author
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. Confirmed with the same literal/escaped PNG pair: core detection and byte extraction accept both, while Ollama's image decoder, the A2A URI accessor, and hosting MCP/A2A conversion reject the escaped form. This PR's helper fix does not establish adapter-wide parity. Since implementation was handed over to LI (@ktz03), these consumer paths and parity tests should be coordinated in the replacement scope with the core team. No provider or transport code has been changed here; this thread remains open. |
||
| ) | ||
|
|
||
|
|
||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Calling
unquotein the shared parser also runs duringContent.from_uri()validation, even though_validate_uridiscardspayload. A percent-heavy URI can makeunquotepeak at roughly 18x the input size (for example, 3 MB produced about 56 MB of transient allocation), and the Responses hosting parser accepts request-ownedinput_imagevalues without a length guard, so concurrent requests can exhaust process memory before any provider handles the image. Please avoid decoding on validation-only paths and enforce a payload limit before percent-decoding in consumers that need the payload.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Confirmed offline:
Content.from_uri()performs payload decoding on the validation-only path even though that path only needs metadata. Decoding should be deferred to consumers that need the payload; a new size-limit policy needs maintainer agreement. Implementation was handed over to @ktz03, so I am leaving this finding open for the replacement PR rather than expanding #9664 in parallel.