@@ -29,20 +29,16 @@ void AsyncWebServerRequest::send(FS &fs, const String &path, const char *content
29
29
const String gzPath = path + asyncsrv::T__gz;
30
30
File gzFile = fs.open (gzPath, fs::FileOpenMode::read);
31
31
32
- // Compressed file not found or invalid
33
- if (!gzFile.seek (gzFile.size () - 8 )) {
34
- send (404 );
35
- gzFile.close ();
36
- return ;
37
- }
38
-
39
32
// ETag validation
40
33
if (this ->hasHeader (asyncsrv::T_INM)) {
41
34
// Generate server ETag from CRC in gzip trailer
42
- uint8_t crcInTrailer[4 ];
43
- gzFile.read (crcInTrailer, 4 );
44
35
char serverETag[9 ];
45
- _getEtag (crcInTrailer, serverETag);
36
+ if (!_getEtag (gzFile, serverETag)) {
37
+ // Compressed file not found or invalid
38
+ send (404 );
39
+ gzFile.close ();
40
+ return ;
41
+ }
46
42
47
43
// Compare with client's ETag
48
44
const AsyncWebHeader *inmHeader = this ->getHeader (asyncsrv::T_INM);
@@ -59,27 +55,36 @@ void AsyncWebServerRequest::send(FS &fs, const String &path, const char *content
59
55
}
60
56
61
57
/* *
62
- * @brief Generates an ETag string from a 4-byte trailer
58
+ * @brief Generates an ETag string from the CRC32 trailer of a GZIP file.
59
+ *
60
+ * This function reads the CRC32 checksum (4 bytes) located at the end of a GZIP-compressed file
61
+ * and converts it into an 8-character hexadecimal ETag string (null-terminated).
63
62
*
64
- * This function converts a 4-byte array into a hexadecimal ETag string enclosed in quotes.
63
+ * @param gzFile Opened file handle pointing to the GZIP file.
64
+ * @param eTag Output buffer to store the generated ETag.
65
+ * Must be pre-allocated with at least 9 bytes (8 for hex digits + 1 for null terminator).
65
66
*
66
- * @param trailer[4] Input array of 4 bytes to convert to hexadecimal
67
- * @param serverETag Output buffer to store the ETag
68
- * Must be pre-allocated with minimum 9 bytes (8 hex + 1 null terminator)
67
+ * @return true if the ETag was successfully generated, false otherwise (e.g., file too short or seek failed).
69
68
*/
70
- void AsyncWebServerRequest::_getEtag (uint8_t trailer[ 4 ] , char *serverETag ) {
69
+ bool AsyncWebServerRequest::_getEtag (File gzFile , char *etag ) {
71
70
static constexpr char hexChars[] = " 0123456789ABCDEF" ;
72
71
73
- uint32_t data;
74
- memcpy (&data, trailer, 4 );
72
+ if (!gzFile.seek (gzFile.size () - 8 )) {
73
+ return false ;
74
+ }
75
+
76
+ uint32_t crc;
77
+ gzFile.read (reinterpret_cast <uint8_t *>(&crc), sizeof (crc));
78
+
79
+ etag[0 ] = hexChars[(crc >> 4 ) & 0x0F ];
80
+ etag[1 ] = hexChars[crc & 0x0F ];
81
+ etag[2 ] = hexChars[(crc >> 12 ) & 0x0F ];
82
+ etag[3 ] = hexChars[(crc >> 8 ) & 0x0F ];
83
+ etag[4 ] = hexChars[(crc >> 20 ) & 0x0F ];
84
+ etag[5 ] = hexChars[(crc >> 16 ) & 0x0F ];
85
+ etag[6 ] = hexChars[(crc >> 28 )];
86
+ etag[7 ] = hexChars[(crc >> 24 ) & 0x0F ];
87
+ etag[8 ] = ' \0 ' ;
75
88
76
- serverETag[0 ] = hexChars[(data >> 4 ) & 0x0F ];
77
- serverETag[1 ] = hexChars[data & 0x0F ];
78
- serverETag[2 ] = hexChars[(data >> 12 ) & 0x0F ];
79
- serverETag[3 ] = hexChars[(data >> 8 ) & 0x0F ];
80
- serverETag[4 ] = hexChars[(data >> 20 ) & 0x0F ];
81
- serverETag[5 ] = hexChars[(data >> 16 ) & 0x0F ];
82
- serverETag[6 ] = hexChars[(data >> 28 )];
83
- serverETag[7 ] = hexChars[(data >> 24 ) & 0x0F ];
84
- serverETag[8 ] = ' \0 ' ;
89
+ return true ;
85
90
}
0 commit comments