Read report/label templates in binary mode - #12432
Conversation
✅ Deploy Preview for inventree-web-pui-preview ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
3c24d4e to
d8c143b
Compare
|
Updated after a self-review:
|
|
@impuls42 thanks for the fix, this seems clean |
|
This is the same issue as #12410 |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## master #12432 +/- ##
=======================================
Coverage 86.87% 86.88%
=======================================
Files 1442 1442
Lines 94942 94971 +29
Branches 11101 11101
=======================================
+ Hits 82482 82511 +29
Misses 12395 12395
Partials 65 65
Flags with carried forward coverage won't be shown. Click here to find out more.
🚀 New features to boost your workflow:
|
|
Added a regression test ( |
8ade6ab to
83b3461
Compare
file_from_template read the template in text mode and wrapped the string in a ContentFile. The ContentFile size then reflected the character count, which differs from the UTF-8 byte length for any template that contains multi-byte characters. Strict S3 implementations such as Backblaze B2 validate the Content-Length header and reject the upload with an IncompleteBody error. AWS S3 tolerates the mismatch, so the problem is not visible there. inventree_transfer_order_report.html is 1458 characters but 1460 bytes. Its upload fails during create_default_reports, the transaction rolls back, and the default template is recreated and fails again on every startup. Use Path.read_bytes() so the ContentFile size matches the uploaded bytes and the file handle is closed. Add a regression test asserting the size equals the file's byte length.
83b3461 to
44b845b
Compare
|
@impuls42 thanks for the contribution! |
💚 All backports created successfully
Questions ?Please refer to the Backport tool documentation and see the Github Action logs for details |
* Read report/label templates in binary mode file_from_template read the template in text mode and wrapped the string in a ContentFile. The ContentFile size then reflected the character count, which differs from the UTF-8 byte length for any template that contains multi-byte characters. Strict S3 implementations such as Backblaze B2 validate the Content-Length header and reject the upload with an IncompleteBody error. AWS S3 tolerates the mismatch, so the problem is not visible there. inventree_transfer_order_report.html is 1458 characters but 1460 bytes. Its upload fails during create_default_reports, the transaction rolls back, and the default template is recreated and fails again on every startup. Use Path.read_bytes() so the ContentFile size matches the uploaded bytes and the file handle is closed. Add a regression test asserting the size equals the file's byte length. * Test file_from_template across text encodings (cherry picked from commit ce47cda) Co-authored-by: Alex K <alex@sengine.cloud>

Fix
file_from_templatereads default report and label templates in text mode, so the resultingContentFilereports its size as a character count. For a template with multi-byte UTF-8 characters that count is smaller than the encoded byte length, and django-storages sends it as theContent-Length. Backblaze B2 and other strict S3 backends reject the upload withIncompleteBody. AWS S3 tolerates the mismatch, so the bug is not visible there.inventree_transfer_order_report.htmlis the only default template with a non-ASCII character (1458 chars, 1460 bytes), so its upload fails duringcreate_default_reports, the transaction rolls back, and it is retried on every startup.Reading the file in binary mode makes
ContentFile.sizematch the uploaded bytes.Fixes #12431
Testing
Reproduced on a live instance backed by Backblaze B2. Before the change,
create_default_reportsfails for the transfer-order template on every startup withIncompleteBody. After the change the template is created and the error is gone. Confirmed the mechanism in a shell for the same file:ContentFile(open(path, 'r').read())fails,ContentFile(open(path, 'rb').read())succeeds.The mismatch only shows up against an S3 backend that enforces Content-Length, so it is not reproducible against the local storage used in CI.