@@ -36,7 +36,7 @@ Add to your `platformio.ini`:
3636
3737``` ini
3838lib_deps =
39- https://github.com/ ESP32Async/AsyncTCP.git
39+ ESP32Async/AsyncTCP @ ^3.4.8
4040 https://github.com/playmiel/ESPAsyncWebClient.git
4141platform_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:
101101If ` 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
121138uint32_t del(const char* url, SuccessCallback onSuccess, ErrorCallback onError = nullptr);
@@ -127,7 +144,7 @@ uint32_t head(const char* url, SuccessCallback onSuccess, ErrorCallback onError
127144uint32_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
133150bool 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;
197214typedef 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
204221int 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;
209226const std::vector<HttpHeader >& getHeaders() const;
210- const String& getTrailer(const String& name) const;
227+ String getTrailer(const String& name) const;
211228const std::vector<HttpHeader >& getTrailers() const;
212229
213230// Response body
214- const String& getBody() const;
231+ String getBody() const;
215232size_t getContentLength() const;
216233
217234// Status helpers
@@ -223,7 +240,7 @@ bool isError() const; // 4xx+ status codes
223240Example 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
254271HTTP 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
264281client.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");
278295String jsonData = " {\" sensor\" :\" temperature\" ,\" value\" :25.5}" ;
279296
280297client.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");
301318client.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 ") );
305322request->setHeader("Authorization", "Bearer token");
306- client.request(request, onSuccess);
323+ client.request(std::move( request) , onSuccess);
307324```
308325
309326### Following Redirects
310327
311328```cpp
312329client.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) );
368385request->setTimeout(30000); // 30 second timeout for this request
369386request->setHeader("Content-Type", "application/xml");
370387request->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:
397414Notes:
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
4754931 . ` 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 ` .
4774953 . Once connected the fully built HTTP request is written (` buildHttpRequest() ` ).
4784964 . 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
483501For 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
514532client.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) {
0 commit comments