@@ -29,20 +29,16 @@ void AsyncWebServerRequest::send(FS &fs, const String &path, const char *content
2929 const String gzPath = path + asyncsrv::T__gz;
3030 File gzFile = fs.open (gzPath, fs::FileOpenMode::read);
3131
32- // Compressed file not found or invalid
33- if (!gzFile.seek (gzFile.size () - 8 )) {
34- send (404 );
35- gzFile.close ();
36- return ;
37- }
38-
3932 // ETag validation
4033 if (this ->hasHeader (asyncsrv::T_INM)) {
4134 // Generate server ETag from CRC in gzip trailer
42- uint8_t crcInTrailer[4 ];
43- gzFile.read (crcInTrailer, 4 );
4435 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+ }
4642
4743 // Compare with client's ETag
4844 const AsyncWebHeader *inmHeader = this ->getHeader (asyncsrv::T_INM);
@@ -59,27 +55,36 @@ void AsyncWebServerRequest::send(FS &fs, const String &path, const char *content
5955}
6056
6157/* *
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).
6362 *
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).
6566 *
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).
6968 */
70- void AsyncWebServerRequest::_getEtag (uint8_t trailer[ 4 ] , char *serverETag ) {
69+ bool AsyncWebServerRequest::_getEtag (File gzFile , char *etag ) {
7170 static constexpr char hexChars[] = " 0123456789ABCDEF" ;
7271
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 ' ;
7588
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 ;
8590}
0 commit comments