Skip to content

Commit 9a74181

Browse files
authored
Merge pull request #18 from playmiel/dev
1.1.4
2 parents 6d9a309 + 5e32254 commit 9a74181

21 files changed

Lines changed: 2438 additions & 137 deletions

.github/workflows/lint.yml

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,8 @@ jobs:
1515
run: sudo apt-get update && sudo apt-get install -y clang-format
1616
- name: Check formatting
1717
run: |
18-
files=$(git ls-files '*.h' '*.cpp' '*.ino')
18+
# Exclude vendored third-party sources from formatting checks.
19+
files=$(git ls-files '*.h' '*.cpp' '*.ino' | grep -v '^src/third_party/' || true)
1920
echo "Checking clang-format on: $files"
2021
diff_found=0
2122
for f in $files; do
@@ -33,7 +34,11 @@ jobs:
3334
run: pip install cpplint
3435
- name: Run cpplint
3536
run: |
36-
cpplint --recursive --extensions=h,cpp src || true
37+
# Keep third_party out of lint noise.
38+
files=$(git ls-files src | grep -E '\\.(h|cpp)$' | grep -v '^src/third_party/' || true)
39+
if [ -n "$files" ]; then
40+
cpplint $files || true
41+
fi
3742
# We don't fail hard yet; adjust policy later
3843
cppcheck:
3944
runs-on: ubuntu-latest
@@ -45,7 +50,7 @@ jobs:
4550
run: |
4651
cppcheck --enable=warning,style,performance --inline-suppr \
4752
--suppress=missingIncludeSystem \
48-
-I src --quiet src || true
53+
-I src --quiet src --exclude=src/third_party || true
4954
version-sync:
5055
runs-on: ubuntu-latest
5156
steps:

.github/workflows/test.yml

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -199,14 +199,17 @@ jobs:
199199
path: |
200200
~/.platformio/.cache
201201
key: ${{ runner.os }}-pio-${{ hashFiles('platformio.ini') }}
202-
- name: Run native unit tests (UrlParser)
202+
- name: Run native unit tests (UrlParser + gzip)
203203
if: ${{ hashFiles('test/**') != '' }}
204204
run: |
205205
echo "Detected test files:" $(ls test || true)
206-
pio test -e native -f test_urlparser_native -v
206+
pio test -e native -f test_urlparser_native -f test_gzip_decode_native -v
207207
- name: Skip notice (no tests found)
208208
if: ${{ hashFiles('test/**') == '' }}
209209
run: echo "No test directory present in this ref; skipping native tests."
210+
- name: Compile ESP32 (gzip enabled)
211+
run: |
212+
pio run -e compile_test_gzip -v
210213
211214
python-parse-tests:
212215
runs-on: ubuntu-latest

README.md

Lines changed: 34 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77

88
An asynchronous HTTP client library for ESP32 microcontrollers, built on top of AsyncTCP. This library provides a simple and efficient way to make HTTP requests without blocking your main program execution.
99

10-
> 🔐 **HTTPS Ready**: TLS/HTTPS is available via AsyncTCP + mbedTLS. Load a CA certificate or fingerprint before talking to real servers, or call `client.setTlsInsecure(true)` only for testing. See the *HTTPS / TLS configuration* section below.
10+
> 🔐 **HTTPS Ready**: TLS/HTTPS is available via AsyncTCP + mbedTLS. Load a CA certificate or fingerprint before talking to real servers. `client.setTlsInsecure(true)` is intended for debug/pinning scenarios; fully insecure TLS requires an explicit build-time opt-in (see the *HTTPS / TLS configuration* section below).
1111
1212
## Features
1313

@@ -167,12 +167,26 @@ void setKeepAlive(bool enable, uint16_t idleMs = 5000);
167167
168168
// Cookie jar helpers
169169
void clearCookies();
170+
void setAllowCookieDomainAttribute(bool enable);
171+
void addAllowedCookieDomain(const char* domain);
172+
void clearAllowedCookieDomains();
170173
void setCookie(const char* name, const char* value, const char* path = "/", const char* domain = nullptr,
171174
bool secure = false);
175+
176+
// Redirect header policy (when followRedirects is enabled)
177+
void setRedirectHeaderPolicy(RedirectHeaderPolicy policy);
178+
void addRedirectSafeHeader(const char* name);
179+
void clearRedirectSafeHeaders();
172180
```
173181

174182
Cookies are captured automatically from `Set-Cookie` responses and replayed on matching hosts/paths; call
175-
`clearCookies()` to wipe the jar or `setCookie()` to pre-seed entries manually. Keep-alive pooling is off by default;
183+
`clearCookies()` to wipe the jar or `setCookie()` to pre-seed entries manually.
184+
185+
By default, cookies set without a `Domain=` attribute are treated as **host-only** (sent only to the exact host that
186+
set them). `Domain=` attributes that would widen scope are ignored unless explicitly allowlisted via
187+
`setAllowCookieDomainAttribute(true)` + `addAllowedCookieDomain("example.com")`.
188+
189+
Keep-alive pooling is off by default;
176190
enable it with `setKeepAlive(true, idleMs)` to reuse TCP/TLS connections for the same host/port (respecting server
177191
`Connection: close` requests).
178192

@@ -304,7 +318,8 @@ client.post("http://example.com/login", "user=demo", [](AsyncHttpResponse* respo
304318

305319
- 301/302/303 responses switch to `GET` automatically (body dropped).
306320
- 307/308 keep the original method and body (stream bodies cannot be replayed automatically).
307-
- Sensitive headers (`Authorization`, `Proxy-Authorization`) are stripped when the redirect crosses hosts.
321+
- Cross-origin redirects default to forwarding only a small safe set of headers (e.g. `User-Agent`, `Accept`, etc.).
322+
Use `setRedirectHeaderPolicy(...)` and `addRedirectSafeHeader(...)` if you need to forward additional headers.
308323
- Redirects are triggered as soon as the headers arrive; the client skips downloading any subsequent 3xx body data.
309324

310325
See `examples/arduino/NoStoreToSD/NoStoreToSD.ino` for a full download example using `setNoStoreBody(true)` and a global `onBodyChunk` handler that streams chunked and non-chunked responses to an SD card.
@@ -409,9 +424,11 @@ Highlights / limitations:
409424

410425
`https://` URLs now use the built-in AsyncTCP + mbedTLS transport. Supply trust material before making real requests:
411426

412-
- `client.setTlsCACert(caPem)` — load a PEM CA chain (null-terminated). Mandatory unless using fingerprint pinning or `setTlsInsecure(true)`.
427+
- `client.setTlsCACert(caPem)` — load a PEM CA chain (null-terminated). Mandatory unless using fingerprint pinning (see `setTlsFingerprint(...)`).
413428
- `client.setTlsClientCert(certPem, keyPem)` — optional mutual-TLS credentials (PEM).
414429
- `client.setTlsFingerprint("AA:BB:...")` — 32-byte SHA-256 fingerprint pinning. Validated after the handshake in addition to CA checks.
430+
- `client.setTlsInsecure(true)` — skips CA validation. By default this is only effective when a fingerprint is configured (pinning).
431+
To allow fully insecure TLS (MITM-unsafe) for local debugging, build with `-DASYNC_HTTP_ALLOW_INSECURE_TLS=1`.
415432
- `client.setTlsInsecure(true)` — disable CA validation (development only; do not ship with this enabled).
416433
- `client.setTlsHandshakeTimeout(ms)` — default is 12s; tune for slow networks.
417434

@@ -451,7 +468,7 @@ Common HTTPS errors:
451468
- Redirects disabled by default; opt-in via `client.setFollowRedirects(...)`
452469
- No long-lived keep-alive: default header `Connection: close`; no connection reuse currently.
453470
- Manual timeout loop required if AsyncTCP version lacks `setTimeout` (call `client.loop()` in `loop()`).
454-
- No specific content-encoding handling (gzip/deflate ignored if sent).
471+
- No general content-encoding handling (br/deflate not supported); optional `gzip` decode is available via `ASYNC_HTTP_ENABLE_GZIP_DECODE`.
455472

456473
## Object lifecycle / Ownership
457474

@@ -488,6 +505,7 @@ Single authoritative list (kept in sync with `HttpCommon.h`):
488505
| -15 | TLS_CERT_INVALID | TLS certificate validation failed |
489506
| -16 | TLS_FINGERPRINT_MISMATCH | TLS fingerprint pinning rejected the peer certificate |
490507
| -17 | TLS_HANDSHAKE_TIMEOUT | TLS handshake exceeded the configured timeout |
508+
| -18 | GZIP_DECODE_FAILED | Failed to decode gzip body (`Content-Encoding: gzip`) |
491509
| >0 | (AsyncTCP) | Not used: transport errors are mapped to CONNECTION_FAILED |
492510

493511
Example mapping in a callback:
@@ -560,7 +578,7 @@ Contributions are welcome! Please feel free to submit a Pull Request.
560578
- Global body chunk callback (per-request callback removed for API simplicity)
561579
- Basic Auth helper (request->setBasicAuth)
562580
- Query param builder (addQueryParam/finalizeQueryParams)
563-
- Optional Accept-Encoding: gzip (no automatic decompression yet)
581+
- Optional Accept-Encoding: gzip (+ optional transparent decode via `ASYNC_HTTP_ENABLE_GZIP_DECODE`)
564582
- Separate connect timeout and total timeout
565583
- Optional request queue limiting parallel connections (setMaxParallel)
566584
- Soft response buffering guard (`setMaxBodySize`) to fail fast on oversized payloads
@@ -569,11 +587,17 @@ Contributions are welcome! Please feel free to submit a Pull Request.
569587

570588
### Gzip / Compression
571589

572-
Current: only the `Accept-Encoding: gzip` header can be added via `enableGzipAcceptEncoding(true)`.
573-
The library DOES NOT yet decompress gzip payloads. If you don't want compressed responses, simply don't enable the header.
590+
Default: only the `Accept-Encoding: gzip` header can be added via `enableGzipAcceptEncoding(true)`.
591+
592+
Optional decode: build with `-DASYNC_HTTP_ENABLE_GZIP_DECODE=1` to transparently inflate `Content-Encoding: gzip` responses (both in-memory body and `client.onBodyChunk(...)` stream).
593+
594+
Notes:
574595

575-
Important: calling `enableGzipAcceptEncoding(false)` does not remove the header if it was already added earlier on the same request instance. Create a new request without enabling it to avoid sending the header.
576-
A future optional flag (`ASYNC_HTTP_ENABLE_GZIP_DECODE`) may add a tiny inflater (miniz/zlib) after flash/RAM impact is evaluated.
596+
- If you don't want compressed responses, simply don't enable the header.
597+
- `enableGzipAcceptEncoding(false)` removes `Accept-Encoding` from the request's header list (or call `request.removeHeader("Accept-Encoding")`).
598+
- `Content-Length` (when present) refers to the *compressed* payload size; completion detection still follows the wire length.
599+
- RAM impact: enabling gzip decode allocates an internal 32KB sliding window per active gzip-decoded response (plus small state).
600+
- Integrity: the gzip trailer is verified (CRC32 + ISIZE); corrupted payloads raise `GZIP_DECODE_FAILED`.
577601

578602
### HTTPS quick reference
579603

library.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "ESPAsyncWebClient",
3-
"version": "1.1.3",
3+
"version": "1.1.4",
44
"description": "Asynchronous HTTP client library for ESP32 ",
55
"keywords": [
66
"http",

library.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
name=ESPAsyncWebClient
2-
version=1.1.3
2+
version=1.1.4
33
author=playmiel
44
maintainer=playmiel
55
sentence=Asynchronous HTTP client library for ESP32 microcontrollers

platformio.ini

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ framework = arduino
1818
platform_packages =
1919
framework-arduinoespressif32@^3
2020
; Run only Arduino-suitable tests on the device build
21-
test_filter = test_parse_url, test_chunk_parse, test_keep_alive, test_cookies
21+
test_filter = test_parse_url, test_chunk_parse, test_keep_alive, test_cookies, test_redirects
2222
test_ignore = test_urlparser_native
2323
lib_deps =
2424
https://github.com/ESP32Async/AsyncTCP.git
@@ -38,6 +38,20 @@ build_src_filter = -<*> +<../src/> +<../test/compile_test_internal/compile_test.
3838
lib_deps =
3939
https://github.com/ESP32Async/AsyncTCP.git
4040

41+
[env:compile_test_gzip]
42+
platform = espressif32
43+
board = esp32dev
44+
framework = arduino
45+
platform_packages =
46+
framework-arduinoespressif32@^3
47+
build_flags =
48+
${env.build_flags}
49+
-DCOMPILE_TEST_ONLY
50+
-DASYNC_HTTP_ENABLE_GZIP_DECODE=1
51+
build_src_filter = -<*> +<../src/> +<../test/compile_test_internal/compile_test.cpp>
52+
lib_deps =
53+
https://github.com/ESP32Async/AsyncTCP.git
54+
4155

4256
# Environment for testing with different AsyncTCP versions
4357
[env:esp32dev_asynctcp_dev]
@@ -74,7 +88,8 @@ platform = native
7488
; Only build the standalone URL parser for host tests to avoid Arduino deps
7589
; Do not compile Arduino-based tests in native
7690
test_ignore = test_parse_url, test_chunk_parse, test_redirects, test_cookies, test_keep_alive
77-
build_src_filter = -<*> +<UrlParser.cpp>
91+
build_src_filter = -<*> +<UrlParser.cpp> +<GzipDecoder.cpp> +<third_party/miniz/miniz_tinfl.c>
7892
build_flags =
7993
-I test/test_urlparser_native
80-
94+
-I src
95+
-DASYNC_HTTP_ENABLE_GZIP_DECODE=1

0 commit comments

Comments
 (0)