You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
fix(api): preserve binary percent-encoded data URI payloads - #681
Preserve binary bytes when decoding percent-encoded data URI payloads.
The non-base64 parser currently calls unquote, which decodes the payload as UTF-8 text, then re-encodes that text. Non-UTF-8 bytes are replaced or rejected. A valid 77-byte PNG produced by DataURI.make(..., base64=False) becomes 97 bytes and is rejected as ImageCorruption; the same PNG works when base64-encoded.
Use unquote_to_bytes for non-base64 payloads, matching the octet representation in RFC 2397 section 2. When the helper receives text, encode it with the declared charset before percent-quoting. Binary helper input is not transcoded. Base64 payload handling and filename decoding are unchanged.
Compatibility
Default UTF-8 and ASCII text retain their behavior. Text helper calls with a declared charset continue to round-trip, and their emitted payload now matches that charset. For example, Latin-1 café is emitted as caf%E9 rather than incorrectly labeled UTF-8 caf%C3%A9.
Previously persisted non-base64 URIs whose declared charset did not match their percent-encoded bytes may decode differently. Regenerate those payloads using their actual declared encoding. This correction does not add charset or media-type validation.
Validation
Linux, Python 3.12.14. Schema/HTTP checks used NumPy 1.26.4, Pillow 12.3.0, Pydantic 2.14.1, FastAPI 0.115.2, and httpx 0.28.1.
29 passed after the change, including the two adjacent schema tests.
The final DataURI test file gives 10 failed, 17 passed against unchanged 040269b and 27 passed with the fix.
Tests cover all 256 byte values, bytes with declared charsets, default/explicit UTF-8 and Latin-1 text, base64 controls, filenames, file helpers, literal plus/percent characters, and generated PNG bytes through actual request validation and image decoding.
The focused schema command explicitly bypasses the root test conftest, whose sentence_transformers dependency is absent from this minimal server environment. These tests use no root-conftest fixtures. This is not a full-suite result.
A separate local HTTP reproduction used the real FastAPI routes, engine, native batching workers, and Pillow decoder with a deterministic pixel-mean model fixture. Both /embeddings with image modality and /embeddings_image return 200 with identical embeddings for percent-encoded and base64 PNGs after the change; the percent-encoded cases returned 400 before. No pretrained model was downloaded or tested.
In a separate existing CPU test environment with the normal root conftest:
DO_NOT_TRACK=1 HF_HUB_OFFLINE=1 python -m pytest \
tests/unit_test/test_engine.py::test_async_api_debug \
tests/unit_test/test_engine.py::test_args_between_array_and_engine_same \
tests/unit_test/test_sync_engine.py::test_sync_engine \
tests/unit_test/test_sync_engine.py::test_sync_engine_double \
tests/unit_test/inference/test_select_model.py \
tests/unit_test/test_args.py \
-k 'not torch and not optimum and not ctranslate2' -q -p no:cacheprovider
Full-source mypy output is identical on the branch and unchanged baseline: 22 missing-optional-dependency errors in 14 files, including the existing pydantic_core import error. This is not a clean type-check pass.
Full make precommit, full pytest, accelerator, and pretrained-model suites were not run.
Checklist
Read the contribution guidelines.
Added regression tests.
Documented data URI payload encodings.
AI assistance was used to prepare this contribution.
Preserves binary bytes in percent-encoded data URIs and makes text passed to DataURI.make use its declared charset.
Percent-encoded data URIs keep their original bytes.
Acknowledgment: linjiaye929 explicitly documents that previously saved payloads with bytes that do not match their declared charset may decode differently. This compatibility change is intentional.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Preserve binary bytes when decoding percent-encoded data URI payloads.
The non-base64 parser currently calls
unquote, which decodes the payload as UTF-8 text, then re-encodes that text. Non-UTF-8 bytes are replaced or rejected. A valid 77-byte PNG produced byDataURI.make(..., base64=False)becomes 97 bytes and is rejected asImageCorruption; the same PNG works when base64-encoded.Use
unquote_to_bytesfor non-base64 payloads, matching the octet representation in RFC 2397 section 2. When the helper receives text, encode it with the declared charset before percent-quoting. Binary helper input is not transcoded. Base64 payload handling and filename decoding are unchanged.Compatibility
Default UTF-8 and ASCII text retain their behavior. Text helper calls with a declared charset continue to round-trip, and their emitted payload now matches that charset. For example, Latin-1
caféis emitted ascaf%E9rather than incorrectly labeled UTF-8caf%C3%A9.Previously persisted non-base64 URIs whose declared charset did not match their percent-encoded bytes may decode differently. Regenerate those payloads using their actual declared encoding. This correction does not add charset or media-type validation.
Validation
Linux, Python 3.12.14. Schema/HTTP checks used NumPy 1.26.4, Pillow 12.3.0, Pydantic 2.14.1, FastAPI 0.115.2, and httpx 0.28.1.
From
libs/infinity_emb:PYTHONPATH=$PWD DO_NOT_TRACK=1 HF_HUB_OFFLINE=1 python -m pytest \ --confcutdir tests/unit_test/fastapi_schemas \ tests/unit_test/fastapi_schemas -q -p no:cacheprovider040269band 27 passed with the fix.sentence_transformersdependency is absent from this minimal server environment. These tests use no root-conftest fixtures. This is not a full-suite result./embeddingswith image modality and/embeddings_imagereturn 200 with identical embeddings for percent-encoded and base64 PNGs after the change; the percent-encoded cases returned 400 before. No pretrained model was downloaded or tested.In a separate existing CPU test environment with the normal root conftest:
DO_NOT_TRACK=1 HF_HUB_OFFLINE=1 python -m pytest \ tests/unit_test/test_engine.py::test_async_api_debug \ tests/unit_test/test_engine.py::test_args_between_array_and_engine_same \ tests/unit_test/test_sync_engine.py::test_sync_engine \ tests/unit_test/test_sync_engine.py::test_sync_engine_double \ tests/unit_test/inference/test_select_model.py \ tests/unit_test/test_args.py \ -k 'not torch and not optimum and not ctranslate2' -q -p no:cacheproviderruff check ., changed-file formatting, codespell, andgit diff --checkpass.pydantic_coreimport error. This is not a clean type-check pass.make precommit, full pytest, accelerator, and pretrained-model suites were not run.Checklist
AI assistance was used to prepare this contribution.