-
Notifications
You must be signed in to change notification settings - Fork 52
Support for pre-compressed and ETag in download #222
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
Support for pre-compressed and ETag in download #222
Conversation
When downloading file request: 1. **Gzipped file serving**: - Automatically detects and serves pre-compressed `.gz` files when uncompressed originals are missing - Properly sets `Content-Encoding: gzip` headers - Implements `If-None-Match` header comparison for 304 (Not Modified) responses (RFC 7232) - Implements `ETag` header using CRC-32 from gzip trailer (bytes 4-7 from end) - Optimize for speed Changes affect: void AsyncWebServerRequest::send(FS &fs, const String &path, const char *contentType, bool download, AwsTemplateProcessor callback) AsyncWebServerResponse * AsyncWebServerRequest::beginResponse(FS &fs, const String &path, const char *contentType, bool download, AwsTemplateProcessor callback) AsyncFileResponse::AsyncFileResponse(FS &fs, const String &path, const char *contentType, bool download, AwsTemplateProcessor callback) : AsyncAbstractResponse(callback)
Implemented as #219 |
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.
Pull Request Overview
This PR enhances file downloads by automatically serving pre-compressed .gz
files when originals are missing, adding gzip headers, and implementing CRC32-based ETag handling for 304 responses.
- Fallback to gzip-compressed file in
AsyncFileResponse
, settingContent-Encoding
,ETag
, andCache-Control
. - Refactor
AsyncWebServerRequest::send()
to check uncompressed first, handle compressed files, and respond304 Not Modified
when ETags match. - Simplify Content-Disposition logic for inline vs. download modes.
Reviewed Changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.
File | Description |
---|---|
src/WebResponses.cpp | Updated AsyncFileResponse constructor to support gzip fallback, ETag generation, and download/inline headers. |
src/AsyncWebServerRequest.cpp | Refactored send() to pre-check uncompressed files, open and validate .gz files, and implement ETag-based 304 logic. |
Comments suppressed due to low confidence (1)
src/WebResponses.cpp:716
- No tests cover the scenario where a corrupted or invalid gzip file triggers a 404 response; add unit tests to validate this path.
_code = 404;
src/AsyncWebServerRequest.cpp
Outdated
if (file && file.size() >= 18) { // 18 is the minimum size of valid gzip file | ||
file.seek(file.size() - 8); | ||
// Handle compressed version | ||
const String gzPath = path + asyncsrv::T__gz; |
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.
The download
flag is ignored when serving compressed files. You should skip serving the .gz
version if download
is true
to respect the download mode.
const String gzPath = path + asyncsrv::T__gz; | |
const String gzPath = path + asyncsrv::T__gz; | |
// Skip serving compressed file if download is true | |
if (download) { | |
send(404); | |
return; | |
} |
Copilot uses AI. Check for mistakes.
Thanks @JosePineiro ! Let's get this PR merged, then I will cut a new release. |
Co-authored-by: Copilot <[email protected]>
Tomorrow I'll submit another PR with a speed improvement for the _setContentTypeFromPath function. |
When downloading file request:
.gz
files when uncompressed originals are missingContent-Encoding: gzip
headersIf-None-Match
header comparison for 304 (Not Modified) responses (RFC 7232)ETag
header using CRC-32 from gzip trailer (bytes 4-7 from end)void AsyncWebServerRequest::send(FS &fs, const String &path, const char *contentType, bool download, AwsTemplateProcessor callback) AsyncWebServerResponse *
AsyncWebServerRequest::beginResponse(FS &fs, const String &path, const char *contentType, bool download, AwsTemplateProcessor callback)
AsyncFileResponse::AsyncFileResponse(FS &fs, const String &path, const char *contentType, bool download, AwsTemplateProcessor callback)
: AsyncAbstractResponse(callback)