Skip to content

Commit 69842f4

Browse files
authored
fix: etag (#46)
* fix: etag * fix: github pl
1 parent 75d77d5 commit 69842f4

File tree

8 files changed

+327
-212
lines changed

8 files changed

+327
-212
lines changed

.github/workflows/ci-dev.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ jobs:
1111
runs-on: ubuntu-latest
1212
strategy:
1313
matrix:
14-
node-version: [22.x, 20.x, 18.x]
14+
node-version: [24.x, 22.x, 20.x]
1515

1616
steps:
1717
- uses: actions/checkout@v4

CHANGELOG.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,21 @@ All notable changes to this project will be documented in this file.
55
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
66
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

8+
## [1.9.3] - 2025-11-01
9+
10+
### Added
11+
12+
- ETag validation support for ESP-IDF engine (`httpd_req_get_hdr_value_len` and `httpd_req_get_hdr_value_str`)
13+
- HTTP 304 Not Modified response handling for ESP-IDF engine, matching behavior of other engines
14+
15+
### Changed
16+
17+
- Optimized generated C++ code for ESPAsyncWebServer engine:
18+
- Optimized If-None-Match header lookups (single call instead of `hasHeader()` + `getHeader()`)
19+
- Removed unnecessary `String()` temporary objects in ETag comparisons (use `.equals()` directly)
20+
- Optimized generated C++ code for PsychicHttpServer engines (psychic, psychic2):
21+
- Removed unnecessary `String()` temporary objects in ETag comparisons (use `.equals()` directly)
22+
823
## [1.9.2] - 2025-10-18
924

1025
### Changed

CLAUDE.md

Lines changed: 36 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -81,8 +81,12 @@ npx tsx src/index.ts -e psychic -s ./demo/svelte/dist -o ./output.h --etag=true
8181
1. **File Collection** (`src/file.ts`): Scans source directory recursively using glob, skips pre-compressed files (.gz, .br) if originals exist, detects duplicate files via SHA256 hashing
8282
2. **Content Analysis** (`src/index.ts`): Determines MIME types using `mime-types` library, calculates MD5 hashes for ETag generation, groups files by extension for statistics
8383
3. **Compression** (`src/index.ts`): Applies gzip level 9 compression, uses compressed version only when size reduction >15% and original >1024 bytes
84-
4. **Code Generation** (`src/cppCode.ts`, `src/cppCodeEspIdf.ts`): Uses Handlebars templates with custom helpers (switch/case), generates engine-specific C++ code with conditional compilation support
85-
5. **Output**: Writes optimized header with embedded binary data arrays, route handlers, ETag strings, and C++ defines for validation
84+
4. **Code Generation** (`src/cppCode.ts`, `src/cppCodeEspIdf.ts`): Uses Handlebars templates with custom helpers (switch/case), generates optimized engine-specific C++ code with:
85+
- Inlined lambda handlers (ESPAsyncWebServer)
86+
- Optimized header lookups for ETag validation (all engines)
87+
- Proper const-correctness and modern C++ patterns
88+
- Conditional compilation support for etag/gzip options
89+
5. **Output**: Writes optimized header with embedded binary data arrays, route handlers with ETag validation, ETag MD5 strings, and C++ defines for build-time validation
8690

8791
### Supported Engines
8892

@@ -94,11 +98,12 @@ npx tsx src/index.ts -e psychic -s ./demo/svelte/dist -o ./output.h --etag=true
9498
### Key Features
9599

96100
- **Automatic Gzip Compression**: Compresses assets when size reduction >15% and >1024 bytes
97-
- **ETag Support**: HTTP cache validation for reduced network traffic
101+
- **ETag Support**: HTTP cache validation for reduced network traffic with 304 Not Modified responses across all engines (psychic, psychic2, async, espidf)
98102
- **Cache Control**: Configurable browser caching with `--cachetime`
99103
- **Multi-Engine Support**: Generate code for different ESP web server libraries
100104
- **File Type Analysis**: Groups files by extension with count statistics
101105
- **Memory Optimization**: Binary data stored as const arrays in program memory
106+
- **Optimized C++ Code**: Generated code uses modern C++ best practices with minimal overhead
102107

103108
## Development Environment
104109

@@ -131,6 +136,8 @@ The `package.script` executable generates 36 test header files (9 combinations o
131136
- `index.html` or `index.htm` files are automatically set as the default route for "/"
132137
- Pre-compressed files (.gz, .br, .brottli) in the source directory are skipped if the original file exists
133138
- The build uses `--clean` and `--force` flags to ensure clean builds without incremental compilation
139+
- ESP-IDF engine includes required headers (`string.h`, `stdlib.h`) for ETag validation support
140+
- All engines now fully support HTTP 304 Not Modified responses for efficient caching
134141

135142
## Template System
136143

@@ -141,6 +148,32 @@ The code generation uses Handlebars with custom helpers:
141148
- **Engine-specific templates**: Each engine (psychic, psychic2, async, espidf) has its own template in `src/cppCode.ts` or `src/cppCodeEspIdf.ts`
142149
- **Data transformation**: Binary content is converted to comma-separated byte arrays in the template data
143150

151+
## Generated C++ Code Quality
152+
153+
The generated C++ code follows modern best practices and is optimized for performance and maintainability:
154+
155+
### ETag Validation Implementation
156+
157+
All four engines support ETag validation with HTTP 304 Not Modified responses:
158+
159+
- **ESPAsyncWebServer (`async`)**: Uses `const AsyncWebHeader*` for proper const-correctness, single `getHeader()` call instead of `hasHeader()` + `getHeader()`, inlined lambda handlers
160+
- **PsychicHttpServer (`psychic`, `psychic2`)**: Uses `request->header().equals()` for direct string comparison without temporary objects
161+
- **ESP-IDF (`espidf`)**: Uses `httpd_req_get_hdr_value_len()` and `httpd_req_get_hdr_value_str()` for header validation with proper memory management (malloc/free)
162+
163+
### Code Optimizations
164+
165+
- **No intermediate variables**: Lambda handlers are inlined directly in route registration (ESPAsyncWebServer)
166+
- **Optimized header lookups**: Single API call instead of redundant checks
167+
- **No temporary String objects**: Uses `.equals()` method directly instead of `== String()` wrapper
168+
- **Proper const-correctness**: All pointer declarations use `const` where appropriate
169+
- **Minimal overhead**: Generated code has minimal runtime performance impact
170+
171+
### Memory Management
172+
173+
- **ESP32 (psychic, psychic2, espidf)**: Const arrays automatically placed in program memory (flash)
174+
- **ESP8266 (async)**: PROGMEM directive explicitly used for flash storage
175+
- **ESP-IDF ETag validation**: Temporary header value buffers are properly allocated and freed
176+
144177
## Generated C++ Defines
145178

146179
The generated header file includes C++ defines for build-time validation:

README.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -175,7 +175,7 @@ const char * etag_assets_index_Soe6cpLA_css = "d4f23bc45ef67890ab12...";
175175
void initSvelteStaticFiles(PsychicHttpServer * server) {
176176
server->on("/assets/index-KwubEIf-.js", HTTP_GET, [](PsychicRequest * request) {
177177
if (request->hasHeader("If-None-Match") &&
178-
request->header("If-None-Match") == String(etag_assets_index_KwubEIf__js)) {
178+
request->header("If-None-Match").equals(etag_assets_index_KwubEIf__js)) {
179179
PsychicResponse response304(request);
180180
response304.setCode(304);
181181
return response304.send();
@@ -192,7 +192,7 @@ void initSvelteStaticFiles(PsychicHttpServer * server) {
192192

193193
server->on("/assets/index-Soe6cpLA.css", HTTP_GET, [](PsychicRequest * request) {
194194
if (request->hasHeader("If-None-Match") &&
195-
request->header("If-None-Match") == String(etag_assets_index_Soe6cpLA_css)) {
195+
request->header("If-None-Match").equals(etag_assets_index_Soe6cpLA_css)) {
196196
PsychicResponse response304(request);
197197
response304.setCode(304);
198198
return response304.send();
@@ -242,6 +242,8 @@ Since microcontroller data traffic is moderately expensive, it is an individual
242242

243243
The use of ETag is **not enabled by default**, this can be achieved with the `--etag=true` switch.
244244

245+
All four engines (psychic, psychic2, async, espidf) fully support ETag validation with HTTP 304 Not Modified responses, reducing bandwidth usage when clients have valid cached content.
246+
245247
> This setting has three states: yes, no, and compiler mode is available. In compiler mode, you can disable/enable ETag by setting the `SVELTEESP32_ENABLE_ETAG` c++ compiler directive. For example, if using platformio, just type `-D SVELTEESP32_ENABLE_ETAG`.
246248
247249
### Cache-control

0 commit comments

Comments
 (0)