@@ -35,7 +35,7 @@ void AsyncWebServerRequest::send(FS &fs, const String &path, const char *content
3535 // ETag validation
3636 if (this ->hasHeader (asyncsrv::T_INM)) {
3737 // Generate server ETag from CRC in gzip trailer
38- char serverETag[9 ];
38+ char serverETag[11 ];
3939 if (!_getEtag (gzFile, serverETag)) {
4040 // Compressed file not found or invalid
4141 send (404 );
@@ -58,14 +58,15 @@ void AsyncWebServerRequest::send(FS &fs, const String &path, const char *content
5858}
5959
6060/* *
61- * @brief Generates an ETag string from the CRC32 trailer of a GZIP file.
61+ * @brief Generates an ETag string (enclosed into quotes) from the CRC32 trailer of a GZIP file.
6262 *
6363 * This function reads the CRC32 checksum (4 bytes) located at the end of a GZIP-compressed file
64- * and converts it into an 8-character hexadecimal ETag string (null-terminated).
64+ * and converts it into an 8-character hexadecimal ETag string (enclosed in double quotes and null-terminated).
65+ * Double quotes for ETag value are required by RFC9110 section 8.8.3.
6566 *
6667 * @param gzFile Opened file handle pointing to the GZIP file.
6768 * @param eTag Output buffer to store the generated ETag.
68- * Must be pre-allocated with at least 9 bytes (8 for hex digits + 1 for null terminator).
69+ * Must be pre-allocated with at least 11 bytes (8 for hex digits + 2 for quotes + 1 for null terminator).
6970 *
7071 * @return true if the ETag was successfully generated, false otherwise (e.g., file too short or seek failed).
7172 */
@@ -79,15 +80,17 @@ bool AsyncWebServerRequest::_getEtag(File gzFile, char *etag) {
7980 uint32_t crc;
8081 gzFile.read (reinterpret_cast <uint8_t *>(&crc), sizeof (crc));
8182
82- etag[0 ] = hexChars[(crc >> 4 ) & 0x0F ];
83- etag[1 ] = hexChars[crc & 0x0F ];
84- etag[2 ] = hexChars[(crc >> 12 ) & 0x0F ];
85- etag[3 ] = hexChars[(crc >> 8 ) & 0x0F ];
86- etag[4 ] = hexChars[(crc >> 20 ) & 0x0F ];
87- etag[5 ] = hexChars[(crc >> 16 ) & 0x0F ];
88- etag[6 ] = hexChars[(crc >> 28 )];
89- etag[7 ] = hexChars[(crc >> 24 ) & 0x0F ];
90- etag[8 ] = ' \0 ' ;
83+ etag[0 ] = ' "' ;
84+ etag[1 ] = hexChars[(crc >> 4 ) & 0x0F ];
85+ etag[2 ] = hexChars[crc & 0x0F ];
86+ etag[3 ] = hexChars[(crc >> 12 ) & 0x0F ];
87+ etag[4 ] = hexChars[(crc >> 8 ) & 0x0F ];
88+ etag[5 ] = hexChars[(crc >> 20 ) & 0x0F ];
89+ etag[6 ] = hexChars[(crc >> 16 ) & 0x0F ];
90+ etag[7 ] = hexChars[(crc >> 28 )];
91+ etag[8 ] = hexChars[(crc >> 24 ) & 0x0F ];
92+ etag[9 ] = ' "' ;
93+ etag[10 ] = ' \0 ' ;
9194
9295 return true ;
9396}
0 commit comments