Skip to content

Commit 50fa208

Browse files
authored
Merge pull request #19 from playmiel/dev
2.0
2 parents 9a74181 + 06af501 commit 50fa208

52 files changed

Lines changed: 2111 additions & 1818 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/build.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ jobs:
120120
platform = espressif32
121121
board = esp32dev
122122
lib_deps =
123-
https://github.com/ESP32Async/AsyncTCP.git
123+
ESP32Async/AsyncTCP @ ^3.4.8
124124
bblanchon/ArduinoJson@^6.21.0
125125
EOF
126126

.github/workflows/test.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ jobs:
1919
platform: [esp32dev]
2020
include:
2121
- platform: esp32dev
22-
async-tcp-repo: "https://github.com/ESP32Async/AsyncTCP.git"
22+
async-tcp-repo: "ESP32Async/AsyncTCP @ ^3.4.8"
2323
test-name: "latest"
2424

2525
steps:
@@ -178,7 +178,7 @@ jobs:
178178
framework = arduino
179179
$PLATFORM_PACKAGES
180180
lib_deps =
181-
https://github.com/ESP32Async/AsyncTCP.git
181+
ESP32Async/AsyncTCP @ ^3.4.8
182182
bblanchon/ArduinoJson@^6.21.0
183183
EOF
184184

README.md

Lines changed: 52 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ Add to your `platformio.ini`:
3636

3737
```ini
3838
lib_deps =
39-
https://github.com/ESP32Async/AsyncTCP.git
39+
ESP32Async/AsyncTCP @ ^3.4.8
4040
https://github.com/playmiel/ESPAsyncWebClient.git
4141
platform_packages =
4242
framework-arduinoespressif32@^3
@@ -70,7 +70,7 @@ void setup() {
7070

7171
// Make a simple GET request
7272
client.get("http://httpbin.org/get",
73-
[](AsyncHttpResponse* response) {
73+
[](std::shared_ptr<AsyncHttpResponse> response) {
7474
Serial.printf("Success! Status: %d\n", response->getStatusCode());
7575
Serial.printf("Body: %s\n", response->getBody().c_str());
7676
},
@@ -101,6 +101,23 @@ On ESP32, if AsyncTCP lacks native timeout support, you have two options:
101101
If `ASYNC_TCP_HAS_TIMEOUT` is available in your AsyncTCP, neither is required for timeouts, but calling
102102
`client.loop()` remains harmless.
103103

104+
## Migration v1 → v2
105+
106+
- `SuccessCallback` now receives `std::shared_ptr<AsyncHttpResponse>`.
107+
- `request()` now takes `std::unique_ptr<AsyncHttpRequest>` and assumes ownership.
108+
- `getBody()`, `getHeader()`, and `getStatusText()` return `String` by value.
109+
- `HttpHeader` names are normalized to lowercase.
110+
- Legacy void-return helpers (`*_legacy`, `ASYNC_HTTP_LEGACY_VOID_API`) were removed.
111+
- `parseChunkSizeLine()` is now private.
112+
- `BodyChunkCallback` data is only valid during the callback; copy if needed.
113+
114+
Example migration for advanced requests:
115+
116+
```cpp
117+
std::unique_ptr<AsyncHttpRequest> request(new AsyncHttpRequest(HTTP_METHOD_GET, "http://example.com"));
118+
client.request(std::move(request), onSuccess, onError);
119+
```
120+
104121
## API Reference
105122
106123
### AsyncHttpClient Class
@@ -109,13 +126,13 @@ If `ASYNC_TCP_HAS_TIMEOUT` is available in your AsyncTCP, neither is required fo
109126
110127
```cpp
111128
// GET request
112-
void get(const char* url, SuccessCallback onSuccess, ErrorCallback onError = nullptr);
129+
uint32_t get(const char* url, SuccessCallback onSuccess, ErrorCallback onError = nullptr);
113130
114131
// POST request with data
115-
void post(const char* url, const char* data, SuccessCallback onSuccess, ErrorCallback onError = nullptr);
132+
uint32_t post(const char* url, const char* data, SuccessCallback onSuccess, ErrorCallback onError = nullptr);
116133
117134
// PUT request with data
118-
void put(const char* url, const char* data, SuccessCallback onSuccess, ErrorCallback onError = nullptr);
135+
uint32_t put(const char* url, const char* data, SuccessCallback onSuccess, ErrorCallback onError = nullptr);
119136
120137
// DELETE request
121138
uint32_t del(const char* url, SuccessCallback onSuccess, ErrorCallback onError = nullptr);
@@ -127,7 +144,7 @@ uint32_t head(const char* url, SuccessCallback onSuccess, ErrorCallback onError
127144
uint32_t patch(const char* url, const char* data, SuccessCallback onSuccess, ErrorCallback onError = nullptr);
128145
129146
// Advanced request (custom method, headers, streaming, etc.)
130-
uint32_t request(AsyncHttpRequest* request, SuccessCallback onSuccess, ErrorCallback onError = nullptr);
147+
uint32_t request(std::unique_ptr<AsyncHttpRequest> request, SuccessCallback onSuccess, ErrorCallback onError = nullptr);
131148
132149
// Abort a request by its ID
133150
bool abort(uint32_t requestId);
@@ -193,7 +210,7 @@ enable it with `setKeepAlive(true, idleMs)` to reuse TCP/TLS connections for the
193210
#### Callback Types
194211
195212
```cpp
196-
typedef std::function<void(AsyncHttpResponse*)> SuccessCallback;
213+
typedef std::function<void(std::shared_ptr<AsyncHttpResponse>)> SuccessCallback;
197214
typedef std::function<void(HttpClientError, const char*)> ErrorCallback;
198215
```
199216

@@ -202,16 +219,16 @@ typedef std::function<void(HttpClientError, const char*)> ErrorCallback;
202219
```cpp
203220
// Response status
204221
int getStatusCode() const;
205-
const String& getStatusText() const;
222+
String getStatusText() const;
206223

207224
// Response headers
208-
const String& getHeader(const String& name) const;
225+
String getHeader(const String& name) const;
209226
const std::vector<HttpHeader>& getHeaders() const;
210-
const String& getTrailer(const String& name) const;
227+
String getTrailer(const String& name) const;
211228
const std::vector<HttpHeader>& getTrailers() const;
212229

213230
// Response body
214-
const String& getBody() const;
231+
String getBody() const;
215232
size_t getContentLength() const;
216233

217234
// Status helpers
@@ -223,7 +240,7 @@ bool isError() const; // 4xx+ status codes
223240
Example of reading decoded chunk trailers:
224241
225242
```cpp
226-
client.get("http://example.com/chunked", [](AsyncHttpResponse* response) {
243+
client.get("http://example.com/chunked", [](std::shared_ptr<AsyncHttpResponse> response) {
227244
for (const auto& trailer : response->getTrailers()) {
228245
Serial.printf("Trailer %s: %s\n", trailer.name.c_str(), trailer.value.c_str());
229246
}
@@ -234,21 +251,21 @@ client.get("http://example.com/chunked", [](AsyncHttpResponse* response) {
234251

235252
```cpp
236253
// Create custom request
237-
AsyncHttpRequest request(HTTP_METHOD_POST, "http://example.com/api");
254+
std::unique_ptr<AsyncHttpRequest> request(new AsyncHttpRequest(HTTP_METHOD_POST, "http://example.com/api"));
238255

239256
// Set headers
240-
request.setHeader("Content-Type", "application/json");
241-
request.setHeader("Authorization", "Bearer token");
242-
request.removeHeader("Accept-Encoding");
257+
request->setHeader("Content-Type", "application/json");
258+
request->setHeader("Authorization", "Bearer token");
259+
request->removeHeader("Accept-Encoding");
243260

244261
// Set body
245-
request.setBody("{\"key\":\"value\"}");
262+
request->setBody("{\"key\":\"value\"}");
246263

247264
// Set timeout
248-
request.setTimeout(10000);
265+
request->setTimeout(10000);
249266

250267
// Execute
251-
client.request(&request, onSuccess, onError);
268+
client.request(std::move(request), onSuccess, onError);
252269
```
253270
254271
HTTP method enums are now prefixed (`HTTP_METHOD_GET`, `HTTP_METHOD_POST`, etc.) to avoid collisions with
@@ -262,7 +279,7 @@ including `ESPAsyncWebServer.h` in the same translation unit).
262279
263280
```cpp
264281
client.get("http://api.example.com/data",
265-
[](AsyncHttpResponse* response) {
282+
[](std::shared_ptr<AsyncHttpResponse> response) {
266283
if (response->isSuccess()) {
267284
Serial.println("Data received:");
268285
Serial.println(response->getBody());
@@ -278,7 +295,7 @@ client.setHeader("Content-Type", "application/json");
278295
String jsonData = "{\"sensor\":\"temperature\",\"value\":25.5}";
279296

280297
client.post("http://api.example.com/sensor", jsonData.c_str(),
281-
[](AsyncHttpResponse* response) {
298+
[](std::shared_ptr<AsyncHttpResponse> response) {
282299
Serial.printf("Posted data, status: %d\n", response->getStatusCode());
283300
}
284301
);
@@ -301,17 +318,17 @@ client.setHeader("X-API-Key", "your-api-key");
301318
client.setUserAgent("MyDevice/1.0");
302319

303320
// Or set per-request headers
304-
AsyncHttpRequest* request = new AsyncHttpRequest(HTTP_METHOD_GET, "http://example.com");
321+
std::unique_ptr<AsyncHttpRequest> request(new AsyncHttpRequest(HTTP_METHOD_GET, "http://example.com"));
305322
request->setHeader("Authorization", "Bearer token");
306-
client.request(request, onSuccess);
323+
client.request(std::move(request), onSuccess);
307324
```
308325
309326
### Following Redirects
310327
311328
```cpp
312329
client.setFollowRedirects(true, 3); // follow at most 3 hops
313330
314-
client.post("http://example.com/login", "user=demo", [](AsyncHttpResponse* response) {
331+
client.post("http://example.com/login", "user=demo", [](std::shared_ptr<AsyncHttpResponse> response) {
315332
Serial.printf("Final location responded with %d\n", response->getStatusCode());
316333
});
317334
```
@@ -364,7 +381,7 @@ client.setHeader("Accept", "application/json");
364381
### Per-Request Settings
365382

366383
```cpp
367-
AsyncHttpRequest* request = new AsyncHttpRequest(HTTP_METHOD_POST, url);
384+
std::unique_ptr<AsyncHttpRequest> request(new AsyncHttpRequest(HTTP_METHOD_POST, url));
368385
request->setTimeout(30000); // 30 second timeout for this request
369386
request->setHeader("Content-Type", "application/xml");
370387
request->setBody(xmlData);
@@ -373,11 +390,11 @@ request->setBody(xmlData);
373390
## Memory Management
374391
375392
- The library automatically manages memory for standard requests
376-
- For advanced `AsyncHttpRequest` objects, the library takes ownership and will delete them
377-
- Response objects are automatically cleaned up after callbacks complete
393+
- For advanced requests, pass a `std::unique_ptr<AsyncHttpRequest>` to `request()`; ownership transfers to the client
394+
- Success callbacks receive a `std::shared_ptr<AsyncHttpResponse>`; keep a copy if you need the response after the callback
378395
- No manual memory management required for typical usage
379396
380-
> IMPORTANT: The `AsyncHttpResponse*` pointer passed to the success callback is ONLY valid during that callback. Do not store it or references to its internal `String` objects. Copy what you need.
397+
> IMPORTANT: Body chunk data is only valid during `onBodyChunk(...)`. Copy it if you need to keep it.
381398
382399
### Body Streaming (experimental)
383400
@@ -397,6 +414,7 @@ Parameters:
397414
Notes:
398415

399416
- Invoked for every segment (chunk or contiguous data block)
417+
- `data` is only valid during the callback; copy it if you need to retain it
400418
- Unless `req->setNoStoreBody(true)` is enabled, the full body is still accumulated internally
401419
- `final` is invoked just before the success callback
402420
- Keep it lightweight (avoid blocking operations)
@@ -466,19 +484,19 @@ Common HTTPS errors:
466484
- Chunked: trailers parsed and attached to `AsyncHttpResponse::getTrailers()`
467485
- Full in-memory buffering (guard with `setMaxBodySize` or use no-store + chunk callback)
468486
- Redirects disabled by default; opt-in via `client.setFollowRedirects(...)`
469-
- No long-lived keep-alive: default header `Connection: close`; no connection reuse currently.
487+
- Keep-alive pooling is disabled by default; enable it with `setKeepAlive(true, idleMs)`.
470488
- Manual timeout loop required if AsyncTCP version lacks `setTimeout` (call `client.loop()` in `loop()`).
471489
- No general content-encoding handling (br/deflate not supported); optional `gzip` decode is available via `ASYNC_HTTP_ENABLE_GZIP_DECODE`.
472490

473491
## Object lifecycle / Ownership
474492

475493
1. `AsyncHttpClient::makeRequest()` creates a dynamic `AsyncHttpRequest` (or you pass yours to `request()`).
476-
2. `request()` allocates a `RequestContext`, an `AsyncHttpResponse` and an `AsyncClient`.
494+
2. `request()` allocates a `RequestContext`, an `AsyncHttpResponse` and an `AsyncTransport`.
477495
3. Once connected the fully built HTTP request is written (`buildHttpRequest()`).
478496
4. Reception: headers buffered until `\r\n\r\n`, then body accumulation (or chunk decoding).
479-
5. On complete success: success callback invoked with `AsyncHttpResponse*` (valid only during the callback).
480-
6. On error or after success callback returns: `cleanup()` deletes `AsyncClient`, `AsyncHttpRequest`, `AsyncHttpResponse`, `RequestContext`.
481-
7. Do **not** keep any pointer/reference after callback return (it will dangle).
497+
5. On complete success: success callback invoked with `std::shared_ptr<AsyncHttpResponse>`.
498+
6. On error or after success callback returns: `cleanup()` deletes the transport, `AsyncHttpRequest`, and `RequestContext`.
499+
7. The response is freed when the last `shared_ptr` copy is released.
482500

483501
For very large bodies or future streaming options, a hook would be placed inside `handleData` after `headersComplete` before `appendBody`.
484502

@@ -512,7 +530,7 @@ Example mapping in a callback:
512530

513531
```cpp
514532
client.get("http://example.com",
515-
[](AsyncHttpResponse* r) {
533+
[](std::shared_ptr<AsyncHttpResponse> r) {
516534
Serial.printf("OK %d %s\n", r->getStatusCode(), r->getStatusText().c_str());
517535
},
518536
[](HttpClientError e, const char* msg) {

examples/arduino/CustomHeaders/CustomHeaders.ino

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ void setup() {
2121

2222
client.get(
2323
"http://httpbin.org/headers",
24-
[](AsyncHttpResponse* response) {
24+
[](const std::shared_ptr<AsyncHttpResponse>& response) {
2525
Serial.println("Request with custom headers successful!");
2626
Serial.printf("Status: %d\n", response->getStatusCode());
2727
},

examples/arduino/MultipleRequests/MultipleRequests.ino

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ AsyncHttpClient client;
66
int requestCount = 0;
77
int responseCount = 0;
88

9-
void onResponse(AsyncHttpResponse* response, const String& requestName) {
9+
void onResponse(const std::shared_ptr<AsyncHttpResponse>& response, const String& requestName) {
1010
responseCount++;
1111
Serial.printf("[%s] Response %d received!\n", requestName.c_str(), responseCount);
1212
Serial.printf("[%s] Status: %d %s\n", requestName.c_str(), response->getStatusCode(),
@@ -30,12 +30,14 @@ void setup() {
3030

3131
requestCount++;
3232
client.get(
33-
"http://httpbin.org/get", [](AsyncHttpResponse* response) { onResponse(response, "GET"); },
33+
"http://httpbin.org/get",
34+
[](const std::shared_ptr<AsyncHttpResponse>& response) { onResponse(response, "GET"); },
3435
[](HttpClientError error, const char* message) { onError(error, message, "GET"); });
3536

3637
requestCount++;
3738
client.post(
38-
"http://httpbin.org/post", "data=test", [](AsyncHttpResponse* response) { onResponse(response, "POST"); },
39+
"http://httpbin.org/post", "data=test",
40+
[](const std::shared_ptr<AsyncHttpResponse>& response) { onResponse(response, "POST"); },
3941
[](HttpClientError error, const char* message) { onError(error, message, "POST"); });
4042
}
4143

examples/arduino/NoStoreToSD/NoStoreToSD.ino

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,12 +31,12 @@ static bool beginDownload(const char* url, const char* destinationPath) {
3131

3232
currentPath = destinationPath;
3333

34-
AsyncHttpRequest* request = new AsyncHttpRequest(HTTP_METHOD_GET, url);
34+
std::unique_ptr<AsyncHttpRequest> request(new AsyncHttpRequest(HTTP_METHOD_GET, url));
3535
request->setNoStoreBody(true); // only stream via onBodyChunk
3636

3737
uint32_t id = client.request(
38-
request,
39-
[](AsyncHttpResponse* response) {
38+
std::move(request),
39+
[](const std::shared_ptr<AsyncHttpResponse>& response) {
4040
Serial.printf("Download complete (%d). Reported length: %u\r\n", response->getStatusCode(),
4141
static_cast<unsigned int>(response->getContentLength()));
4242
if (!plainQueued) {

examples/arduino/PostWithData/PostWithData.ino

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ void setup() {
1818

1919
client.post(
2020
"http://httpbin.org/post", postData.c_str(),
21-
[](AsyncHttpResponse* response) {
21+
[](const std::shared_ptr<AsyncHttpResponse>& response) {
2222
Serial.println("POST Success!");
2323
Serial.printf("Status: %d\n", response->getStatusCode());
2424
Serial.printf("Content-Type: %s\n", response->getHeader("Content-Type").c_str());

examples/arduino/SimpleGet/SimpleGet.ino

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ void setup() {
1616

1717
client.get(
1818
"http://httpbin.org/get",
19-
[](AsyncHttpResponse* response) {
19+
[](const std::shared_ptr<AsyncHttpResponse>& response) {
2020
Serial.println("Success!");
2121
Serial.printf("Status: %d\n", response->getStatusCode());
2222
Serial.printf("Body: %s\n", response->getBody().c_str());

examples/arduino/StreamingUpload/StreamingUpload.ino

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ void setup() {
4747
pattern.total = 10 * 1024;
4848
pattern.sent = 0;
4949

50-
AsyncHttpRequest* req = new AsyncHttpRequest(HTTP_METHOD_POST, "http://httpbin.org/post");
50+
std::unique_ptr<AsyncHttpRequest> req(new AsyncHttpRequest(HTTP_METHOD_POST, "http://httpbin.org/post"));
5151
req->addQueryParam("mode", "stream");
5252
req->addQueryParam("unit", "bytes");
5353
req->finalizeQueryParams();
@@ -61,8 +61,8 @@ void setup() {
6161
});
6262
req->setBodyStream(pattern.total, patternProvider);
6363
client.request(
64-
req,
65-
[](AsyncHttpResponse* resp) {
64+
std::move(req),
65+
[](const std::shared_ptr<AsyncHttpResponse>& resp) {
6666
Serial.printf("UPLOAD DONE status=%d len=%u\n", resp->getStatusCode(), (unsigned)resp->getBody().length());
6767
},
6868
[](HttpClientError code, const char* msg) { Serial.printf("ERROR %d: %s\n", (int)code, msg); });

examples/platformio/CompileTest/platformio.ini

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,9 @@ platform_packages =
77
monitor_speed = 115200
88

99
lib_deps =
10-
https://github.com/playmiel/ESPAsyncWebClient.git
11-
10+
ESP32Async/AsyncTCP @ ^3.4.8
11+
12+
lib_extra_dirs = ../../../
1213

1314
build_flags =
1415
-DCOMPILE_TEST_ONLY

0 commit comments

Comments
 (0)