Aktualizace na verzi 3.2.4

This commit is contained in:
Pavel Brychta 2024-09-11 19:20:32 +02:00
parent d8ffb99455
commit 3ba4d9d10d
14 changed files with 305 additions and 180 deletions

View File

@ -1,11 +1,13 @@
# ESPAsyncWebServer # ESPAsyncWebServer
[![License: LGPL 3.0](https://img.shields.io/badge/License-LGPL%203.0-yellow.svg)](https://opensource.org/license/lgpl-3-0/)
[![Continuous Integration](https://github.com/mathieucarbou/ESPAsyncWebServer/actions/workflows/ci.yml/badge.svg)](https://github.com/mathieucarbou/ESPAsyncWebServer/actions/workflows/ci.yml)
[![Latest Release](https://img.shields.io/github/release/mathieucarbou/ESPAsyncWebServer.svg)](https://GitHub.com/mathieucarbou/ESPAsyncWebServer/releases/) [![Latest Release](https://img.shields.io/github/release/mathieucarbou/ESPAsyncWebServer.svg)](https://GitHub.com/mathieucarbou/ESPAsyncWebServer/releases/)
[![PlatformIO Registry](https://badges.registry.platformio.org/packages/mathieucarbou/library/ESPAsyncWebServer.svg)](https://registry.platformio.org/libraries/mathieucarbou/ESPAsyncWebServer) [![PlatformIO Registry](https://badges.registry.platformio.org/packages/mathieucarbou/library/ESPAsyncWebServer.svg)](https://registry.platformio.org/libraries/mathieucarbou/ESPAsyncWebServer)
[![License: LGPL 3.0](https://img.shields.io/badge/License-LGPL%203.0-yellow.svg)](https://opensource.org/license/lgpl-3-0/)
[![Contributor Covenant](https://img.shields.io/badge/Contributor%20Covenant-2.1-4baaaa.svg)](code_of_conduct.md)
[![Build](https://github.com/mathieucarbou/ESPAsyncWebServer/actions/workflows/ci.yml/badge.svg)](https://github.com/mathieucarbou/ESPAsyncWebServer/actions/workflows/ci.yml)
[![GitHub latest commit](https://badgen.net/github/last-commit/mathieucarbou/ESPAsyncWebServer)](https://GitHub.com/mathieucarbou/ESPAsyncWebServer/commit/)
[![Gitpod Ready-to-Code](https://img.shields.io/badge/Gitpod-Ready--to--Code-blue?logo=gitpod)](https://gitpod.io/#https://github.com/mathieucarbou/ESPAsyncWebServer) [![Gitpod Ready-to-Code](https://img.shields.io/badge/Gitpod-Ready--to--Code-blue?logo=gitpod)](https://gitpod.io/#https://github.com/mathieucarbou/ESPAsyncWebServer)
Asynchronous HTTP and WebSocket Server Library for ESP32, ESP8266 and RP2040 Asynchronous HTTP and WebSocket Server Library for ESP32, ESP8266 and RP2040
@ -18,12 +20,12 @@ This fork is based on [yubox-node-org/ESPAsyncWebServer](https://github.com/yubo
**WARNING** The library name was changed from `ESP Async WebServer` to `ESPAsyncWebServer` as per the Arduino Lint recommendations. **WARNING** The library name was changed from `ESP Async WebServer` to `ESPAsyncWebServer` as per the Arduino Lint recommendations.
``` ```
mathieucarbou/ESPAsyncWebServer @ 3.2.0 mathieucarbou/ESPAsyncWebServer @ 3.2.4
``` ```
Dependency: Dependency:
- **ESP32**: `mathieucarbou/AsyncTCP @ 3.2.4` (Arduino IDE: [https://github.com/mathieucarbou/AsyncTCP#v3.2.4](https://github.com/mathieucarbou/AsyncTCP/releases/tag/v3.2.0)) - **ESP32**: `mathieucarbou/AsyncTCP @ 3.2.5` (Arduino IDE: [https://github.com/mathieucarbou/AsyncTCP#v3.2.5](https://github.com/mathieucarbou/AsyncTCP/releases))
- **ESP8266**: `esphome/ESPAsyncTCP-esphome @ 2.0.0` (Arduino IDE: [https://github.com/mathieucarbou/esphome-ESPAsyncTCP#v2.0.0](https://github.com/mathieucarbou/esphome-ESPAsyncTCP/releases/tag/v2.0.0)) - **ESP8266**: `esphome/ESPAsyncTCP-esphome @ 2.0.0` (Arduino IDE: [https://github.com/mathieucarbou/esphome-ESPAsyncTCP#v2.0.0](https://github.com/mathieucarbou/esphome-ESPAsyncTCP/releases/tag/v2.0.0))
- **RP2040**: `khoih-prog/AsyncTCP_RP2040W @ 1.2.0` (Arduino IDE: [https://github.com/khoih-prog/AsyncTCP_RP2040W#v1.2.0](https://github.com/khoih-prog/AsyncTCP_RP2040W/releases/tag/v1.2.0)) - **RP2040**: `khoih-prog/AsyncTCP_RP2040W @ 1.2.0` (Arduino IDE: [https://github.com/khoih-prog/AsyncTCP_RP2040W#v1.2.0](https://github.com/khoih-prog/AsyncTCP_RP2040W/releases/tag/v1.2.0))
@ -40,10 +42,9 @@ Dependency:
- [@mathieucarbou](https://github.com/mathieucarbou): Arduino 3 / ESP-IDF 5.1 compatibility - [@mathieucarbou](https://github.com/mathieucarbou): Arduino 3 / ESP-IDF 5.1 compatibility
- [@mathieucarbou](https://github.com/mathieucarbou): Arduino Json 7 compatibility and backward compatible with 6 and 6 (changes in `AsyncJson.h`). The API to use Json has not changed. These are only internal changes. - [@mathieucarbou](https://github.com/mathieucarbou): Arduino Json 7 compatibility and backward compatible with 6 and 6 (changes in `AsyncJson.h`). The API to use Json has not changed. These are only internal changes.
- [@mathieucarbou](https://github.com/mathieucarbou): CI - [@mathieucarbou](https://github.com/mathieucarbou): CI
- [@mathieucarbou](https://github.com/mathieucarbou): Depends on `mathieucarbou/AsyncTCP @ 3.2.4` - [@mathieucarbou](https://github.com/mathieucarbou): Depends on `mathieucarbou/AsyncTCP @ 3.2.5`
- [@mathieucarbou](https://github.com/mathieucarbou): Deployed in PlatformIO registry and Arduino IDE library manager - [@mathieucarbou](https://github.com/mathieucarbou): Deployed in PlatformIO registry and Arduino IDE library manager
- [@mathieucarbou](https://github.com/mathieucarbou): Firmware size optimization: remove mbedtls dependency (accounts for 33KB in firmware) - [@mathieucarbou](https://github.com/mathieucarbou): Firmware size optimization: remove mbedtls dependency (accounts for 33KB in firmware)
- [@mathieucarbou](https://github.com/mathieucarbou): Made DEFAULT_MAX_SSE_CLIENTS customizable
- [@mathieucarbou](https://github.com/mathieucarbou): Made DEFAULT_MAX_WS_CLIENTS customizable - [@mathieucarbou](https://github.com/mathieucarbou): Made DEFAULT_MAX_WS_CLIENTS customizable
- [@mathieucarbou](https://github.com/mathieucarbou): MessagePack Support ([#62](https://github.com/mathieucarbou/ESPAsyncWebServer/pull/62)) - [@mathieucarbou](https://github.com/mathieucarbou): MessagePack Support ([#62](https://github.com/mathieucarbou/ESPAsyncWebServer/pull/62))
- [@mathieucarbou](https://github.com/mathieucarbou): Remove filename after inline in Content-Disposition header according to RFC2183 - [@mathieucarbou](https://github.com/mathieucarbou): Remove filename after inline in Content-Disposition header according to RFC2183

View File

@ -1,11 +1,13 @@
# ESPAsyncWebServer # ESPAsyncWebServer
[![License: LGPL 3.0](https://img.shields.io/badge/License-LGPL%203.0-yellow.svg)](https://opensource.org/license/lgpl-3-0/)
[![Continuous Integration](https://github.com/mathieucarbou/ESPAsyncWebServer/actions/workflows/ci.yml/badge.svg)](https://github.com/mathieucarbou/ESPAsyncWebServer/actions/workflows/ci.yml)
[![Latest Release](https://img.shields.io/github/release/mathieucarbou/ESPAsyncWebServer.svg)](https://GitHub.com/mathieucarbou/ESPAsyncWebServer/releases/) [![Latest Release](https://img.shields.io/github/release/mathieucarbou/ESPAsyncWebServer.svg)](https://GitHub.com/mathieucarbou/ESPAsyncWebServer/releases/)
[![PlatformIO Registry](https://badges.registry.platformio.org/packages/mathieucarbou/library/ESPAsyncWebServer.svg)](https://registry.platformio.org/libraries/mathieucarbou/ESPAsyncWebServer) [![PlatformIO Registry](https://badges.registry.platformio.org/packages/mathieucarbou/library/ESPAsyncWebServer.svg)](https://registry.platformio.org/libraries/mathieucarbou/ESPAsyncWebServer)
[![License: LGPL 3.0](https://img.shields.io/badge/License-LGPL%203.0-yellow.svg)](https://opensource.org/license/lgpl-3-0/)
[![Contributor Covenant](https://img.shields.io/badge/Contributor%20Covenant-2.1-4baaaa.svg)](code_of_conduct.md)
[![Build](https://github.com/mathieucarbou/ESPAsyncWebServer/actions/workflows/ci.yml/badge.svg)](https://github.com/mathieucarbou/ESPAsyncWebServer/actions/workflows/ci.yml)
[![GitHub latest commit](https://badgen.net/github/last-commit/mathieucarbou/ESPAsyncWebServer)](https://GitHub.com/mathieucarbou/ESPAsyncWebServer/commit/)
[![Gitpod Ready-to-Code](https://img.shields.io/badge/Gitpod-Ready--to--Code-blue?logo=gitpod)](https://gitpod.io/#https://github.com/mathieucarbou/ESPAsyncWebServer) [![Gitpod Ready-to-Code](https://img.shields.io/badge/Gitpod-Ready--to--Code-blue?logo=gitpod)](https://gitpod.io/#https://github.com/mathieucarbou/ESPAsyncWebServer)
Asynchronous HTTP and WebSocket Server Library for ESP32, ESP8266 and RP2040 Asynchronous HTTP and WebSocket Server Library for ESP32, ESP8266 and RP2040
@ -18,12 +20,12 @@ This fork is based on [yubox-node-org/ESPAsyncWebServer](https://github.com/yubo
**WARNING** The library name was changed from `ESP Async WebServer` to `ESPAsyncWebServer` as per the Arduino Lint recommendations. **WARNING** The library name was changed from `ESP Async WebServer` to `ESPAsyncWebServer` as per the Arduino Lint recommendations.
``` ```
mathieucarbou/ESPAsyncWebServer @ 3.2.0 mathieucarbou/ESPAsyncWebServer @ 3.2.4
``` ```
Dependency: Dependency:
- **ESP32**: `mathieucarbou/AsyncTCP @ 3.2.4` (Arduino IDE: [https://github.com/mathieucarbou/AsyncTCP#v3.2.4](https://github.com/mathieucarbou/AsyncTCP/releases/tag/v3.2.0)) - **ESP32**: `mathieucarbou/AsyncTCP @ 3.2.5` (Arduino IDE: [https://github.com/mathieucarbou/AsyncTCP#v3.2.5](https://github.com/mathieucarbou/AsyncTCP/releases))
- **ESP8266**: `esphome/ESPAsyncTCP-esphome @ 2.0.0` (Arduino IDE: [https://github.com/mathieucarbou/esphome-ESPAsyncTCP#v2.0.0](https://github.com/mathieucarbou/esphome-ESPAsyncTCP/releases/tag/v2.0.0)) - **ESP8266**: `esphome/ESPAsyncTCP-esphome @ 2.0.0` (Arduino IDE: [https://github.com/mathieucarbou/esphome-ESPAsyncTCP#v2.0.0](https://github.com/mathieucarbou/esphome-ESPAsyncTCP/releases/tag/v2.0.0))
- **RP2040**: `khoih-prog/AsyncTCP_RP2040W @ 1.2.0` (Arduino IDE: [https://github.com/khoih-prog/AsyncTCP_RP2040W#v1.2.0](https://github.com/khoih-prog/AsyncTCP_RP2040W/releases/tag/v1.2.0)) - **RP2040**: `khoih-prog/AsyncTCP_RP2040W @ 1.2.0` (Arduino IDE: [https://github.com/khoih-prog/AsyncTCP_RP2040W#v1.2.0](https://github.com/khoih-prog/AsyncTCP_RP2040W/releases/tag/v1.2.0))
@ -40,10 +42,9 @@ Dependency:
- [@mathieucarbou](https://github.com/mathieucarbou): Arduino 3 / ESP-IDF 5.1 compatibility - [@mathieucarbou](https://github.com/mathieucarbou): Arduino 3 / ESP-IDF 5.1 compatibility
- [@mathieucarbou](https://github.com/mathieucarbou): Arduino Json 7 compatibility and backward compatible with 6 and 6 (changes in `AsyncJson.h`). The API to use Json has not changed. These are only internal changes. - [@mathieucarbou](https://github.com/mathieucarbou): Arduino Json 7 compatibility and backward compatible with 6 and 6 (changes in `AsyncJson.h`). The API to use Json has not changed. These are only internal changes.
- [@mathieucarbou](https://github.com/mathieucarbou): CI - [@mathieucarbou](https://github.com/mathieucarbou): CI
- [@mathieucarbou](https://github.com/mathieucarbou): Depends on `mathieucarbou/AsyncTCP @ 3.2.4` - [@mathieucarbou](https://github.com/mathieucarbou): Depends on `mathieucarbou/AsyncTCP @ 3.2.5`
- [@mathieucarbou](https://github.com/mathieucarbou): Deployed in PlatformIO registry and Arduino IDE library manager - [@mathieucarbou](https://github.com/mathieucarbou): Deployed in PlatformIO registry and Arduino IDE library manager
- [@mathieucarbou](https://github.com/mathieucarbou): Firmware size optimization: remove mbedtls dependency (accounts for 33KB in firmware) - [@mathieucarbou](https://github.com/mathieucarbou): Firmware size optimization: remove mbedtls dependency (accounts for 33KB in firmware)
- [@mathieucarbou](https://github.com/mathieucarbou): Made DEFAULT_MAX_SSE_CLIENTS customizable
- [@mathieucarbou](https://github.com/mathieucarbou): Made DEFAULT_MAX_WS_CLIENTS customizable - [@mathieucarbou](https://github.com/mathieucarbou): Made DEFAULT_MAX_WS_CLIENTS customizable
- [@mathieucarbou](https://github.com/mathieucarbou): MessagePack Support ([#62](https://github.com/mathieucarbou/ESPAsyncWebServer/pull/62)) - [@mathieucarbou](https://github.com/mathieucarbou): MessagePack Support ([#62](https://github.com/mathieucarbou/ESPAsyncWebServer/pull/62))
- [@mathieucarbou](https://github.com/mathieucarbou): Remove filename after inline in Content-Disposition header according to RFC2183 - [@mathieucarbou](https://github.com/mathieucarbou): Remove filename after inline in Content-Disposition header according to RFC2183

View File

@ -25,8 +25,40 @@
#include <LittleFS.h> #include <LittleFS.h>
AsyncWebServer server(80); AsyncWebServer server(80);
AsyncEventSource events("/events");
AsyncWebSocket ws("/ws");
const char* PARAM_MESSAGE = "message"; const char* PARAM_MESSAGE PROGMEM = "message";
const char* SSE_HTLM PROGMEM = R"(
<!DOCTYPE html>
<html>
<head>
<title>Server-Sent Events</title>
<script>
if (!!window.EventSource) {
var source = new EventSource('/events');
source.addEventListener('open', function(e) {
console.log("Events Connected");
}, false);
source.addEventListener('error', function(e) {
if (e.target.readyState != EventSource.OPEN) {
console.log("Events Disconnected");
}
}, false);
source.addEventListener('message', function(e) {
console.log("message", e.data);
}, false);
source.addEventListener('heartbeat', function(e) {
console.log("heartbeat", e.data);
}, false);
}
</script>
</head>
<body>
<h1>Open your browser console!</h1>
</body>
</html>
)";
void notFound(AsyncWebServerRequest* request) { void notFound(AsyncWebServerRequest* request) {
request->send(404, "text/plain", "Not found"); request->send(404, "text/plain", "Not found");
@ -69,12 +101,15 @@ void setup() {
Connection: close Connection: close
Accept-Ranges: bytes Accept-Ranges: bytes
*/ */
// Ref: https://github.com/mathieucarbou/ESPAsyncWebServer/pull/80 // Ref: https://github.com/mathieucarbou/ESPAsyncWebServer/pull/80
server.on("/download", HTTP_HEAD | HTTP_GET, [](AsyncWebServerRequest* request) { server.on("/download", HTTP_HEAD | HTTP_GET, [](AsyncWebServerRequest* request) {
if (request->method() == HTTP_HEAD) { if (request->method() == HTTP_HEAD) {
AsyncWebServerResponse* response = request->beginResponse(200, "application/octet-stream"); AsyncWebServerResponse* response = request->beginResponse(200, "application/octet-stream");
response->setContentLength(1024); // myFile.getSize() response->addHeader(asyncsrv::T_Accept_Ranges, "bytes");
response->addHeader("Accept-Ranges", "bytes"); response->addHeader(asyncsrv::T_Content_Length, 10);
response->setContentLength(1024); // overrides previous one
response->addHeader(asyncsrv::T_Content_Type, "foo");
response->setContentType("application/octet-stream"); // overrides previous one
// ... // ...
request->send(response); request->send(response);
} else { } else {
@ -108,7 +143,7 @@ void setup() {
// receives JSON and sends JSON // receives JSON and sends JSON
jsonHandler->onRequest([](AsyncWebServerRequest* request, JsonVariant& json) { jsonHandler->onRequest([](AsyncWebServerRequest* request, JsonVariant& json) {
JsonObject jsonObj = json.as<JsonObject>(); // JsonObject jsonObj = json.as<JsonObject>();
// ... // ...
AsyncJsonResponse* response = new AsyncJsonResponse(); AsyncJsonResponse* response = new AsyncJsonResponse();
@ -131,7 +166,7 @@ void setup() {
// receives MessagePack and sends MessagePack // receives MessagePack and sends MessagePack
msgPackHandler->onRequest([](AsyncWebServerRequest* request, JsonVariant& json) { msgPackHandler->onRequest([](AsyncWebServerRequest* request, JsonVariant& json) {
JsonObject jsonObj = json.as<JsonObject>(); // JsonObject jsonObj = json.as<JsonObject>();
// ... // ...
AsyncMessagePackResponse* response = new AsyncMessagePackResponse(); AsyncMessagePackResponse* response = new AsyncMessagePackResponse();
@ -150,6 +185,43 @@ void setup() {
request->send(response); request->send(response);
}); });
events.onConnect([](AsyncEventSourceClient* client) {
if (client->lastId()) {
Serial.printf("SSE Client reconnected! Last message ID that it gat is: %" PRIu32 "\n", client->lastId());
}
client->send("hello!", NULL, millis(), 1000);
});
server.on("/sse", HTTP_GET, [](AsyncWebServerRequest* request) {
request->send(200, "text/html", SSE_HTLM);
});
ws.onEvent([](AsyncWebSocket* server, AsyncWebSocketClient* client, AwsEventType type, void* arg, uint8_t* data, size_t len) {
(void) len;
if (type == WS_EVT_CONNECT) {
Serial.println("ws connect");
client->setCloseClientOnQueueFull(false);
client->ping();
} else if (type == WS_EVT_DISCONNECT) {
Serial.println("ws disconnect");
} else if (type == WS_EVT_ERROR) {
Serial.println("ws error");
} else if (type == WS_EVT_PONG) {
Serial.println("ws pong");
} else if (type == WS_EVT_DATA) {
AwsFrameInfo* info = (AwsFrameInfo*)arg;
String msg = "";
if (info->final && info->index == 0 && info->len == len) {
if (info->opcode == WS_TEXT) {
data[len] = 0;
Serial.printf("ws text: %s\n", (char*)data);
}
}
}
});
server.addHandler(&events);
server.addHandler(&ws);
server.addHandler(jsonHandler); server.addHandler(jsonHandler);
server.addHandler(msgPackHandler); server.addHandler(msgPackHandler);
@ -158,5 +230,20 @@ void setup() {
server.begin(); server.begin();
} }
uint32_t lastSSE = 0;
uint32_t deltaSSE = 5;
uint32_t lastWS = 0;
uint32_t deltaWS = 100;
void loop() { void loop() {
uint32_t now = millis();
if (now - lastSSE >= deltaSSE) {
events.send(String("ping-") + now, "heartbeat", now);
lastSSE = millis();
}
if (now - lastWS >= deltaWS) {
ws.printfAll("kp%.4f", (10.0 / 3.0));
lastWS = millis();
}
} }

View File

@ -1,6 +1,6 @@
{ {
"name": "ESPAsyncWebServer", "name": "ESPAsyncWebServer",
"version": "3.2.0", "version": "3.2.4",
"description": "Asynchronous HTTP and WebSocket Server Library for ESP32, ESP8266 and RP2040. Supports: WebSocket, SSE, Authentication, Arduino Json 7, File Upload, Static File serving, URL Rewrite, URL Redirect, etc.", "description": "Asynchronous HTTP and WebSocket Server Library for ESP32, ESP8266 and RP2040. Supports: WebSocket, SSE, Authentication, Arduino Json 7, File Upload, Static File serving, URL Rewrite, URL Redirect, etc.",
"keywords": "http,async,websocket,webserver", "keywords": "http,async,websocket,webserver",
"homepage": "https://github.com/mathieucarbou/ESPAsyncWebServer", "homepage": "https://github.com/mathieucarbou/ESPAsyncWebServer",
@ -28,7 +28,7 @@
{ {
"owner": "mathieucarbou", "owner": "mathieucarbou",
"name": "AsyncTCP", "name": "AsyncTCP",
"version": "^3.2.4", "version": "^3.2.5",
"platforms": "espressif32" "platforms": "espressif32"
}, },
{ {

View File

@ -1,5 +1,5 @@
name=ESPAsyncWebServer name=ESPAsyncWebServer
version=3.2.0 version=3.2.4
author=Me-No-Dev author=Me-No-Dev
maintainer=Mathieu Carbou <mathieu.carbou@gmail.com> maintainer=Mathieu Carbou <mathieu.carbou@gmail.com>
sentence=Asynchronous HTTP and WebSocket Server Library for ESP32, ESP8266 and RP2040 sentence=Asynchronous HTTP and WebSocket Server Library for ESP32, ESP8266 and RP2040

View File

@ -2,6 +2,7 @@
framework = arduino framework = arduino
build_flags = build_flags =
-Wall -Wextra -Wall -Wextra
-Wno-unused-parameter
-D CONFIG_ARDUHAL_LOG_COLORS -D CONFIG_ARDUHAL_LOG_COLORS
-D CORE_DEBUG_LEVEL=ARDUHAL_LOG_LEVEL_VERBOSE -D CORE_DEBUG_LEVEL=ARDUHAL_LOG_LEVEL_VERBOSE
-D CONFIG_ASYNC_TCP_MAX_ACK_TIME=3000 -D CONFIG_ASYNC_TCP_MAX_ACK_TIME=3000
@ -22,19 +23,12 @@ src_dir = examples/SimpleServer
; src_dir = examples/Draft ; src_dir = examples/Draft
; src_dir = examples/issues/Issue14 ; src_dir = examples/issues/Issue14
[env:arduino]
platform = espressif32
board = esp32dev
lib_deps =
bblanchon/ArduinoJson @ 7.1.0
mathieucarbou/AsyncTCP @ 3.2.4
[env:arduino-2] [env:arduino-2]
platform = espressif32@6.8.1 platform = espressif32@6.8.1
board = esp32dev board = esp32dev
lib_deps = lib_deps =
bblanchon/ArduinoJson @ 7.1.0 bblanchon/ArduinoJson @ 7.1.0
mathieucarbou/AsyncTCP @ 3.2.4 mathieucarbou/AsyncTCP @ 3.2.5
[env:arduino-3] [env:arduino-3]
platform = espressif32 platform = espressif32
@ -44,7 +38,7 @@ platform_packages=
board = esp32dev board = esp32dev
lib_deps = lib_deps =
bblanchon/ArduinoJson @ 7.1.0 bblanchon/ArduinoJson @ 7.1.0
mathieucarbou/AsyncTCP @ 3.2.4 mathieucarbou/AsyncTCP @ 3.2.5
[env:esp8266] [env:esp8266]
platform = espressif8266 platform = espressif8266
@ -70,18 +64,18 @@ platform = https://github.com/pioarduino/platform-espressif32/releases/download/
board = esp32dev board = esp32dev
lib_deps = lib_deps =
bblanchon/ArduinoJson @ 7.1.0 bblanchon/ArduinoJson @ 7.1.0
mathieucarbou/AsyncTCP @ 3.2.4 mathieucarbou/AsyncTCP @ 3.2.5
[env:pioarduino-c6] [env:pioarduino-c6]
platform = https://github.com/pioarduino/platform-espressif32/releases/download/51.03.04/platform-espressif32.zip platform = https://github.com/pioarduino/platform-espressif32/releases/download/51.03.04/platform-espressif32.zip
board = esp32-c6-devkitc-1 board = esp32-c6-devkitc-1
lib_deps = lib_deps =
bblanchon/ArduinoJson @ 7.1.0 bblanchon/ArduinoJson @ 7.1.0
mathieucarbou/AsyncTCP @ 3.2.4 mathieucarbou/AsyncTCP @ 3.2.5
[env:pioarduino-h2] [env:pioarduino-h2]
platform = https://github.com/pioarduino/platform-espressif32/releases/download/51.03.04/platform-espressif32.zip platform = https://github.com/pioarduino/platform-espressif32/releases/download/51.03.04/platform-espressif32.zip
board = esp32-h2-devkitm-1 board = esp32-h2-devkitm-1
lib_deps = lib_deps =
bblanchon/ArduinoJson @ 7.1.0 bblanchon/ArduinoJson @ 7.1.0
mathieucarbou/AsyncTCP @ 3.2.4 mathieucarbou/AsyncTCP @ 3.2.5

View File

@ -128,8 +128,7 @@ AsyncEventSourceMessage::~AsyncEventSourceMessage() {
free(_data); free(_data);
} }
size_t AsyncEventSourceMessage::ack(size_t len, uint32_t time) { size_t AsyncEventSourceMessage::ack(size_t len, __attribute__((unused)) uint32_t time) {
(void)time;
// If the whole message is now acked... // If the whole message is now acked...
if (_acked + len > _len) { if (_acked + len > _len) {
// Return the number of extra bytes acked (they will be carried on to the next message) // Return the number of extra bytes acked (they will be carried on to the next message)
@ -142,17 +141,19 @@ size_t AsyncEventSourceMessage::ack(size_t len, uint32_t time) {
return 0; return 0;
} }
// This could also return void as the return value is not used. size_t AsyncEventSourceMessage::write(AsyncClient* client) {
// Leaving as-is for compatibility... if (_sent >= _len || !client->canSend()) {
size_t AsyncEventSourceMessage::send(AsyncClient* client) {
if (_sent >= _len) {
return 0; return 0;
} }
const size_t len_to_send = _len - _sent; size_t len = min(_len - _sent, client->space());
auto position = reinterpret_cast<const char*>(_data + _sent); size_t sent = client->add((const char*)_data + _sent, len);
const size_t sent_now = client->write(position, len_to_send); _sent += sent;
_sent += sent_now; return sent;
return sent_now; }
size_t AsyncEventSourceMessage::send(AsyncClient* client) {
size_t sent = write(client);
return sent && client->send() ? sent : 0;
} }
// Client // Client
@ -174,6 +175,8 @@ AsyncEventSourceClient::AsyncEventSourceClient(AsyncWebServerRequest* request, A
_server->_addClient(this); _server->_addClient(this);
delete request; delete request;
_client->setNoDelay(true);
} }
AsyncEventSourceClient::~AsyncEventSourceClient() { AsyncEventSourceClient::~AsyncEventSourceClient() {
@ -211,11 +214,6 @@ void AsyncEventSourceClient::_onAck(size_t len, uint32_t time) {
// Same here, acquiring the lock early // Same here, acquiring the lock early
std::lock_guard<std::mutex> lock(_lockmq); std::lock_guard<std::mutex> lock(_lockmq);
#endif #endif
while (len && _messageQueue.size()) {
len = _messageQueue.front().ack(len, time);
if (_messageQueue.front().finished())
_messageQueue.pop_front();
}
_runQueue(); _runQueue();
} }
@ -264,11 +262,24 @@ size_t AsyncEventSourceClient::packetsWaiting() const {
} }
void AsyncEventSourceClient::_runQueue() { void AsyncEventSourceClient::_runQueue() {
// Calls to this private method now already protected by _lockmq acquisition size_t total_bytes_written = 0;
// so no extra call of _lockmq.lock() here.. for (auto i = _messageQueue.begin(); i != _messageQueue.end(); ++i) {
for (auto& i : _messageQueue) { if (!i->sent()) {
if (!i.sent()) const size_t bytes_written = i->write(_client);
i.send(_client); total_bytes_written += bytes_written;
if (bytes_written == 0)
break;
}
}
if (total_bytes_written > 0)
_client->send();
size_t len = total_bytes_written;
while (len && _messageQueue.size()) {
len = _messageQueue.front().ack(len);
if (_messageQueue.front().finished()) {
_messageQueue.pop_front();
}
} }
} }
@ -392,7 +403,8 @@ AsyncEventSourceResponse::AsyncEventSourceResponse(AsyncEventSource* server) {
} }
void AsyncEventSourceResponse::_respond(AsyncWebServerRequest* request) { void AsyncEventSourceResponse::_respond(AsyncWebServerRequest* request) {
String out = _assembleHead(request->version()); String out;
_assembleHead(out, request->version());
request->client()->write(out.c_str(), _headLength); request->client()->write(out.c_str(), _headLength);
_state = RESPONSE_WAIT_ACK; _state = RESPONSE_WAIT_ACK;
} }

View File

@ -49,14 +49,6 @@
#endif #endif
#endif #endif
#ifndef DEFAULT_MAX_SSE_CLIENTS
#ifdef ESP32
#define DEFAULT_MAX_SSE_CLIENTS 8
#else
#define DEFAULT_MAX_SSE_CLIENTS 4
#endif
#endif
class AsyncEventSource; class AsyncEventSource;
class AsyncEventSourceResponse; class AsyncEventSourceResponse;
class AsyncEventSourceClient; class AsyncEventSourceClient;
@ -74,7 +66,8 @@ class AsyncEventSourceMessage {
public: public:
AsyncEventSourceMessage(const char* data, size_t len); AsyncEventSourceMessage(const char* data, size_t len);
~AsyncEventSourceMessage(); ~AsyncEventSourceMessage();
size_t ack(size_t len, uint32_t time __attribute__((unused))); size_t ack(size_t len, uint32_t time = 0);
size_t write(AsyncClient* client);
size_t send(AsyncClient* client); size_t send(AsyncClient* client);
bool finished() { return _acked == _len; } bool finished() { return _acked == _len; }
bool sent() { return _sent == _len; } bool sent() { return _sent == _len; }
@ -99,6 +92,8 @@ class AsyncEventSourceClient {
AsyncClient* client() { return _client; } AsyncClient* client() { return _client; }
void close(); void close();
void write(const char* message, size_t len); void write(const char* message, size_t len);
void send(const String& message, const String& event, uint32_t id = 0, uint32_t reconnect = 0) { send(message.c_str(), event.c_str(), id, reconnect); }
void send(const String& message, const char* event, uint32_t id = 0, uint32_t reconnect = 0) { send(message.c_str(), event, id, reconnect); }
void send(const char* message, const char* event = NULL, uint32_t id = 0, uint32_t reconnect = 0); void send(const char* message, const char* event = NULL, uint32_t id = 0, uint32_t reconnect = 0);
bool connected() const { return (_client != NULL) && _client->connected(); } bool connected() const { return (_client != NULL) && _client->connected(); }
uint32_t lastId() const { return _lastId; } uint32_t lastId() const { return _lastId; }
@ -124,13 +119,15 @@ class AsyncEventSource : public AsyncWebHandler {
ArAuthorizeConnectHandler _authorizeConnectHandler; ArAuthorizeConnectHandler _authorizeConnectHandler;
public: public:
AsyncEventSource(const String& url) : _url(url){}; AsyncEventSource(const String& url) : _url(url) {};
~AsyncEventSource() { close(); }; ~AsyncEventSource() { close(); };
const char* url() const { return _url.c_str(); } const char* url() const { return _url.c_str(); }
void close(); void close();
void onConnect(ArEventHandlerFunction cb); void onConnect(ArEventHandlerFunction cb);
void authorizeConnect(ArAuthorizeConnectHandler cb); void authorizeConnect(ArAuthorizeConnectHandler cb);
void send(const String& message, const String& event, uint32_t id = 0, uint32_t reconnect = 0) { send(message.c_str(), event.c_str(), id, reconnect); }
void send(const String& message, const char* event, uint32_t id = 0, uint32_t reconnect = 0) { send(message.c_str(), event, id, reconnect); }
void send(const char* message, const char* event = NULL, uint32_t id = 0, uint32_t reconnect = 0); void send(const char* message, const char* event = NULL, uint32_t id = 0, uint32_t reconnect = 0);
// number of clients connected // number of clients connected
size_t count() const; size_t count() const;

View File

@ -27,7 +27,7 @@
#if defined(ESP32) #if defined(ESP32)
#if ESP_IDF_VERSION_MAJOR < 5 #if ESP_IDF_VERSION_MAJOR < 5
#include "./port/SHA1Builder.h" #include "BackPort_SHA1Builder.h"
#else #else
#include <SHA1Builder.h> #include <SHA1Builder.h>
#endif #endif
@ -36,11 +36,8 @@
#include <Hash.h> #include <Hash.h>
#endif #endif
#define MAX_PRINTF_LEN 64
using namespace asyncsrv; using namespace asyncsrv;
size_t webSocketSendFrameWindow(AsyncClient* client) { size_t webSocketSendFrameWindow(AsyncClient* client) {
if (!client->canSend()) if (!client->canSend())
return 0; return 0;
@ -589,30 +586,23 @@ void AsyncWebSocketClient::_onData(void* pbuf, size_t plen) {
size_t AsyncWebSocketClient::printf(const char* format, ...) { size_t AsyncWebSocketClient::printf(const char* format, ...) {
va_list arg; va_list arg;
va_start(arg, format); va_start(arg, format);
char* temp = new char[MAX_PRINTF_LEN]; size_t len = vsnprintf(nullptr, 0, format, arg);
if (!temp) { va_end(arg);
va_end(arg);
return 0; if (len == 0)
} return 0;
char* buffer = temp;
size_t len = vsnprintf(temp, MAX_PRINTF_LEN, format, arg); char* buffer = new char[len + 1];
if (!buffer)
return 0;
va_start(arg, format);
len = vsnprintf(buffer, len + 1, format, arg);
va_end(arg); va_end(arg);
if (len > (MAX_PRINTF_LEN - 1)) {
buffer = new char[len + 1];
if (!buffer) {
delete[] temp;
return 0;
}
va_start(arg, format);
vsnprintf(buffer, len + 1, format, arg);
va_end(arg);
}
text(buffer, len); text(buffer, len);
if (buffer != temp) { delete[] buffer;
delete[] buffer;
}
delete[] temp;
return len; return len;
} }
@ -620,30 +610,23 @@ size_t AsyncWebSocketClient::printf(const char* format, ...) {
size_t AsyncWebSocketClient::printf_P(PGM_P formatP, ...) { size_t AsyncWebSocketClient::printf_P(PGM_P formatP, ...) {
va_list arg; va_list arg;
va_start(arg, formatP); va_start(arg, formatP);
char* temp = new char[MAX_PRINTF_LEN]; size_t len = vsnprintf_P(nullptr, 0, formatP, arg);
if (!temp) { va_end(arg);
va_end(arg);
return 0; if (len == 0)
} return 0;
char* buffer = temp;
size_t len = vsnprintf_P(temp, MAX_PRINTF_LEN, formatP, arg); char* buffer = new char[len + 1];
if (!buffer)
return 0;
va_start(arg, formatP);
len = vsnprintf_P(buffer, len + 1, formatP, arg);
va_end(arg); va_end(arg);
if (len > (MAX_PRINTF_LEN - 1)) {
buffer = new char[len + 1];
if (!buffer) {
delete[] temp;
return 0;
}
va_start(arg, formatP);
vsnprintf_P(buffer, len + 1, formatP, arg);
va_end(arg);
}
text(buffer, len); text(buffer, len);
if (buffer != temp) { delete[] buffer;
delete[] buffer;
}
delete[] temp;
return len; return len;
} }
#endif #endif
@ -1008,22 +991,24 @@ size_t AsyncWebSocket::printf(uint32_t id, const char* format, ...) {
size_t AsyncWebSocket::printfAll(const char* format, ...) { size_t AsyncWebSocket::printfAll(const char* format, ...) {
va_list arg; va_list arg;
char* temp = new char[MAX_PRINTF_LEN]; va_start(arg, format);
if (!temp) size_t len = vsnprintf(nullptr, 0, format, arg);
va_end(arg);
if (len == 0)
return 0;
char* buffer = new char[len + 1];
if (!buffer)
return 0; return 0;
va_start(arg, format); va_start(arg, format);
size_t len = vsnprintf(temp, MAX_PRINTF_LEN, format, arg); len = vsnprintf(buffer, len + 1, format, arg);
va_end(arg);
delete[] temp;
AsyncWebSocketSharedBuffer buffer = std::make_shared<std::vector<uint8_t>>(len);
va_start(arg, format);
vsnprintf((char*)buffer->data(), len + 1, format, arg);
va_end(arg); va_end(arg);
textAll(buffer); textAll(buffer, len);
delete[] buffer;
return len; return len;
} }
@ -1042,22 +1027,24 @@ size_t AsyncWebSocket::printf_P(uint32_t id, PGM_P formatP, ...) {
size_t AsyncWebSocket::printfAll_P(PGM_P formatP, ...) { size_t AsyncWebSocket::printfAll_P(PGM_P formatP, ...) {
va_list arg; va_list arg;
char* temp = new char[MAX_PRINTF_LEN]; va_start(arg, formatP);
if (!temp) size_t len = vsnprintf_P(nullptr, 0, formatP, arg);
va_end(arg);
if (len == 0)
return 0;
char* buffer = new char[len + 1];
if (!buffer)
return 0; return 0;
va_start(arg, formatP); va_start(arg, formatP);
size_t len = vsnprintf_P(temp, MAX_PRINTF_LEN, formatP, arg); len = vsnprintf_P(buffer, len + 1, formatP, arg);
va_end(arg);
delete[] temp;
AsyncWebSocketSharedBuffer buffer = std::make_shared<std::vector<uint8_t>>(len + 1);
va_start(arg, formatP);
vsnprintf_P((char*)buffer->data(), len + 1, formatP, arg);
va_end(arg); va_end(arg);
textAll(buffer); textAll(buffer, len);
delete[] buffer;
return len; return len;
} }
#endif #endif
@ -1192,7 +1179,8 @@ void AsyncWebSocketResponse::_respond(AsyncWebServerRequest* request) {
request->client()->close(true); request->client()->close(true);
return; return;
} }
String out(_assembleHead(request->version())); String out;
_assembleHead(out, request->version());
request->client()->write(out.c_str(), _headLength); request->client()->write(out.c_str(), _headLength);
_state = RESPONSE_WAIT_ACK; _state = RESPONSE_WAIT_ACK;
} }

View File

@ -23,7 +23,7 @@
#include <Arduino.h> #include <Arduino.h>
#if ESP_IDF_VERSION_MAJOR < 5 #if ESP_IDF_VERSION_MAJOR < 5
#include "SHA1Builder.h" #include "BackPort_SHA1Builder.h"
// 32-bit integer manipulation macros (big endian) // 32-bit integer manipulation macros (big endian)
@ -202,7 +202,7 @@ void SHA1Builder::process(const uint8_t *data) {
// Public methods // Public methods
void SHA1Builder::begin(void) { void SHA1Builder::begin() {
total[0] = 0; total[0] = 0;
total[1] = 0; total[1] = 0;

View File

@ -12,6 +12,9 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
#include <Arduino.h>
#if ESP_IDF_VERSION_MAJOR < 5
#ifndef SHA1Builder_h #ifndef SHA1Builder_h
#define SHA1Builder_h #define SHA1Builder_h
@ -37,3 +40,5 @@ class SHA1Builder {
}; };
#endif // SHA1Builder_h #endif // SHA1Builder_h
#endif // ESP_IDF_VERSION_MAJOR < 5

View File

@ -45,10 +45,10 @@
#include "literals.h" #include "literals.h"
#define ASYNCWEBSERVER_VERSION "3.2.0" #define ASYNCWEBSERVER_VERSION "3.2.4"
#define ASYNCWEBSERVER_VERSION_MAJOR 3 #define ASYNCWEBSERVER_VERSION_MAJOR 3
#define ASYNCWEBSERVER_VERSION_MINOR 2 #define ASYNCWEBSERVER_VERSION_MINOR 2
#define ASYNCWEBSERVER_VERSION_REVISION 0 #define ASYNCWEBSERVER_VERSION_REVISION 4
#define ASYNCWEBSERVER_FORK_mathieucarbou #define ASYNCWEBSERVER_FORK_mathieucarbou
#ifdef ASYNCWEBSERVER_REGEX #ifdef ASYNCWEBSERVER_REGEX
@ -155,7 +155,9 @@ class AsyncWebHeader {
const String& name() const { return _name; } const String& name() const { return _name; }
const String& value() const { return _value; } const String& value() const { return _value; }
String toString() const { String toString() const {
String str = _name; String str;
str.reserve(_name.length() + _value.length() + 2);
str.concat(_name);
str.concat((char)0x3a); str.concat((char)0x3a);
str.concat((char)0x20); str.concat((char)0x20);
str.concat(_value); str.concat(_value);
@ -333,11 +335,15 @@ class AsyncWebServerRequest {
void sendChunked(const char* contentType, AwsResponseFiller callback, AwsTemplateProcessor templateCallback = nullptr) { send(beginChunkedResponse(contentType, callback, templateCallback)); } void sendChunked(const char* contentType, AwsResponseFiller callback, AwsTemplateProcessor templateCallback = nullptr) { send(beginChunkedResponse(contentType, callback, templateCallback)); }
void sendChunked(const String& contentType, AwsResponseFiller callback, AwsTemplateProcessor templateCallback = nullptr) { send(beginChunkedResponse(contentType, callback, templateCallback)); } void sendChunked(const String& contentType, AwsResponseFiller callback, AwsTemplateProcessor templateCallback = nullptr) { send(beginChunkedResponse(contentType, callback, templateCallback)); }
#ifndef ESP8266
[[deprecated("Replaced by send(...)")]] [[deprecated("Replaced by send(...)")]]
#endif
void send_P(int code, const String& contentType, const uint8_t* content, size_t len, AwsTemplateProcessor callback = nullptr) { void send_P(int code, const String& contentType, const uint8_t* content, size_t len, AwsTemplateProcessor callback = nullptr) {
send(code, contentType, content, len, callback); send(code, contentType, content, len, callback);
} }
#ifndef ESP8266
[[deprecated("Replaced by send(...)")]] [[deprecated("Replaced by send(...)")]]
#endif
void send_P(int code, const String& contentType, PGM_P content, AwsTemplateProcessor callback = nullptr) { void send_P(int code, const String& contentType, PGM_P content, AwsTemplateProcessor callback = nullptr) {
send(code, contentType, content, callback); send(code, contentType, content, callback);
} }
@ -370,13 +376,17 @@ class AsyncWebServerRequest {
AsyncResponseStream* beginResponseStream(const char* contentType, size_t bufferSize = 1460); AsyncResponseStream* beginResponseStream(const char* contentType, size_t bufferSize = 1460);
AsyncResponseStream* beginResponseStream(const String& contentType, size_t bufferSize = 1460) { return beginResponseStream(contentType.c_str(), bufferSize); } AsyncResponseStream* beginResponseStream(const String& contentType, size_t bufferSize = 1460) { return beginResponseStream(contentType.c_str(), bufferSize); }
#ifndef ESP8266
[[deprecated("Replaced by beginResponse(...)")]] [[deprecated("Replaced by beginResponse(...)")]]
#endif
AsyncWebServerResponse* beginResponse_P(int code, const String& contentType, const uint8_t* content, size_t len, AwsTemplateProcessor callback = nullptr) { AsyncWebServerResponse* beginResponse_P(int code, const String& contentType, const uint8_t* content, size_t len, AwsTemplateProcessor callback = nullptr) {
return beginResponse(code, contentType, content, len, callback); return beginResponse(code, contentType.c_str(), content, len, callback);
} }
#ifndef ESP8266
[[deprecated("Replaced by beginResponse(...)")]] [[deprecated("Replaced by beginResponse(...)")]]
#endif
AsyncWebServerResponse* beginResponse_P(int code, const String& contentType, PGM_P content, AwsTemplateProcessor callback = nullptr) { AsyncWebServerResponse* beginResponse_P(int code, const String& contentType, PGM_P content, AwsTemplateProcessor callback = nullptr) {
return beginResponse(code, contentType, content, callback); return beginResponse(code, contentType.c_str(), content, callback);
} }
#ifdef ESP8266 #ifdef ESP8266
@ -583,8 +593,21 @@ class AsyncWebServerResponse {
virtual void setContentType(const char* type); virtual void setContentType(const char* type);
virtual bool addHeader(const char* name, const char* value, bool replaceExisting = true); virtual bool addHeader(const char* name, const char* value, bool replaceExisting = true);
bool addHeader(const String& name, const String& value, bool replaceExisting = true) { return addHeader(name.c_str(), value.c_str(), replaceExisting); } bool addHeader(const String& name, const String& value, bool replaceExisting = true) { return addHeader(name.c_str(), value.c_str(), replaceExisting); }
bool addHeader(const char* name, long value, bool replaceExisting = true) { return addHeader(name, String(value), replaceExisting); }
bool addHeader(const String& name, long value, bool replaceExisting = true) { return addHeader(name.c_str(), value, replaceExisting); }
virtual bool removeHeader(const char* name); virtual bool removeHeader(const char* name);
virtual String _assembleHead(uint8_t version); virtual const AsyncWebHeader* getHeader(const char* name) const;
#ifndef ESP8266
[[deprecated("Use instead: _assembleHead(String& buffer, uint8_t version)")]]
#endif
String _assembleHead(uint8_t version) {
String buffer;
_assembleHead(buffer, version);
return buffer;
}
virtual void _assembleHead(String& buffer, uint8_t version);
virtual bool _started() const; virtual bool _started() const;
virtual bool _finished() const; virtual bool _finished() const;
virtual bool _failed() const; virtual bool _failed() const;

View File

@ -624,7 +624,6 @@ bool AsyncWebServerRequest::hasHeader(const __FlashStringHelper* data) const {
const AsyncWebHeader* AsyncWebServerRequest::getHeader(const char* name) const { const AsyncWebHeader* AsyncWebServerRequest::getHeader(const char* name) const {
auto iter = std::find_if(std::begin(_headers), std::end(_headers), [&name](const AsyncWebHeader& header) { return header.name().equalsIgnoreCase(name); }); auto iter = std::find_if(std::begin(_headers), std::end(_headers), [&name](const AsyncWebHeader& header) { return header.name().equalsIgnoreCase(name); });
return (iter == std::end(_headers)) ? nullptr : &(*iter); return (iter == std::end(_headers)) ? nullptr : &(*iter);
} }

View File

@ -125,9 +125,8 @@ const char* AsyncWebServerResponse::responseCodeToString(int code) {
return T_HTTP_CODE_ANY; return T_HTTP_CODE_ANY;
} }
} }
#else // ESP8266 #else // ESP8266
const __FlashStringHelper* AsyncWebServerResponse::responseCodeToString(int code) const __FlashStringHelper* AsyncWebServerResponse::responseCodeToString(int code) {
{
switch (code) { switch (code) {
case 100: case 100:
return FPSTR(T_HTTP_CODE_100); return FPSTR(T_HTTP_CODE_100);
@ -230,12 +229,12 @@ void AsyncWebServerResponse::setCode(int code) {
} }
void AsyncWebServerResponse::setContentLength(size_t len) { void AsyncWebServerResponse::setContentLength(size_t len) {
if (_state == RESPONSE_SETUP) if (_state == RESPONSE_SETUP && addHeader(T_Content_Length, len, true))
_contentLength = len; _contentLength = len;
} }
void AsyncWebServerResponse::setContentType(const char* type) { void AsyncWebServerResponse::setContentType(const char* type) {
if (_state == RESPONSE_SETUP) if (_state == RESPONSE_SETUP && addHeader(T_Content_Type, type, true))
_contentType = type; _contentType = type;
} }
@ -249,6 +248,11 @@ bool AsyncWebServerResponse::removeHeader(const char* name) {
return false; return false;
} }
const AsyncWebHeader* AsyncWebServerResponse::getHeader(const char* name) const {
auto iter = std::find_if(std::begin(_headers), std::end(_headers), [&name](const AsyncWebHeader& header) { return header.name().equalsIgnoreCase(name); });
return (iter == std::end(_headers)) ? nullptr : &(*iter);
}
bool AsyncWebServerResponse::addHeader(const char* name, const char* value, bool replaceExisting) { bool AsyncWebServerResponse::addHeader(const char* name, const char* value, bool replaceExisting) {
for (auto i = _headers.begin(); i != _headers.end(); ++i) { for (auto i = _headers.begin(); i != _headers.end(); ++i) {
if (i->name().equalsIgnoreCase(name)) { if (i->name().equalsIgnoreCase(name)) {
@ -268,41 +272,56 @@ bool AsyncWebServerResponse::addHeader(const char* name, const char* value, bool
return true; return true;
} }
String AsyncWebServerResponse::_assembleHead(uint8_t version) { void AsyncWebServerResponse::_assembleHead(String& buffer, uint8_t version) {
if (version) { if (version) {
addHeader(T_Accept_Ranges, T_none, false); addHeader(T_Accept_Ranges, T_none, false);
if (_chunked) if (_chunked)
addHeader(T_Transfer_Encoding, T_chunked, false); addHeader(T_Transfer_Encoding, T_chunked, false);
} }
String out;
constexpr size_t bufSize = 300;
char buf[bufSize];
#ifndef ESP8266 if (_sendContentLength)
snprintf(buf, bufSize, "HTTP/1.%d %d %s\r\n", version, _code, responseCodeToString(_code)); addHeader(T_Content_Length, String(_contentLength), false);
if (_contentType.length())
addHeader(T_Content_Type, _contentType.c_str(), false);
// precompute buffer size to avoid reallocations by String class
size_t len = 0;
len += 50; // HTTP/1.1 200 <reason>\r\n
for (const auto& header : _headers)
len += header.name().length() + header.value().length() + 4;
// prepare buffer
buffer.reserve(len);
// HTTP header
#ifdef ESP8266
buffer.concat(PSTR("HTTP/1."));
#else #else
snprintf_P(buf, bufSize, PSTR("HTTP/1.%d %d %s\r\n"), version, _code, String(responseCodeToString(_code)).c_str()); buffer.concat("HTTP/1.");
#endif #endif
out.concat(buf); buffer.concat(version);
buffer.concat(' ');
if (_sendContentLength) { buffer.concat(_code);
snprintf_P(buf, bufSize, PSTR("Content-Length: %d\r\n"), _contentLength); buffer.concat(' ');
out.concat(buf); buffer.concat(responseCodeToString(_code));
} buffer.concat(T_rn);
if (_contentType.length()) {
snprintf_P(buf, bufSize, PSTR("Content-Type: %s\r\n"), _contentType.c_str());
out.concat(buf);
}
// Add headers
for (const auto& header : _headers) { for (const auto& header : _headers) {
snprintf_P(buf, bufSize, PSTR("%s: %s\r\n"), header.name().c_str(), header.value().c_str()); buffer.concat(header.name());
out.concat(buf); #ifdef ESP8266
buffer.concat(PSTR(": "));
#else
buffer.concat(": ");
#endif
buffer.concat(header.value());
buffer.concat(T_rn);
} }
_headers.clear(); _headers.clear();
out.concat(T_rn); buffer.concat(T_rn);
_headLength = out.length(); _headLength = buffer.length();
return out;
} }
bool AsyncWebServerResponse::_started() const { return _state > RESPONSE_SETUP; } bool AsyncWebServerResponse::_started() const { return _state > RESPONSE_SETUP; }
@ -337,7 +356,8 @@ AsyncBasicResponse::AsyncBasicResponse(int code, const char* contentType, const
void AsyncBasicResponse::_respond(AsyncWebServerRequest* request) { void AsyncBasicResponse::_respond(AsyncWebServerRequest* request) {
_state = RESPONSE_HEADERS; _state = RESPONSE_HEADERS;
String out = _assembleHead(request->version()); String out;
_assembleHead(out, request->version());
size_t outLen = out.length(); size_t outLen = out.length();
size_t space = request->client()->space(); size_t space = request->client()->space();
if (!_contentLength && space >= outLen) { if (!_contentLength && space >= outLen) {
@ -411,7 +431,7 @@ AsyncAbstractResponse::AsyncAbstractResponse(AwsTemplateProcessor callback) : _c
void AsyncAbstractResponse::_respond(AsyncWebServerRequest* request) { void AsyncAbstractResponse::_respond(AsyncWebServerRequest* request) {
addHeader(T_Connection, T_close, false); addHeader(T_Connection, T_close, false);
_head = _assembleHead(request->version()); _assembleHead(_head, request->version());
_state = RESPONSE_HEADERS; _state = RESPONSE_HEADERS;
_ack(request, 0, 0); _ack(request, 0, 0);
} }
@ -472,9 +492,7 @@ size_t AsyncAbstractResponse::_ack(AsyncWebServerRequest* request, size_t len, u
free(buf); free(buf);
return 0; return 0;
} }
outLen = sprintf_P((char*)buf + headLen, PSTR("%x"), readLen) + headLen; outLen = sprintf((char*)buf+headLen, "%04x", readLen) + headLen;
while (outLen < headLen + 4)
buf[outLen++] = ' ';
buf[outLen++] = '\r'; buf[outLen++] = '\r';
buf[outLen++] = '\n'; buf[outLen++] = '\n';
outLen += readLen; outLen += readLen;
@ -635,9 +653,9 @@ AsyncFileResponse::~AsyncFileResponse() {
void AsyncFileResponse::_setContentTypeFromPath(const String& path) { void AsyncFileResponse::_setContentTypeFromPath(const String& path) {
#if HAVE_EXTERN_GET_Content_Type_FUNCTION #if HAVE_EXTERN_GET_Content_Type_FUNCTION
#ifndef ESP8266 #ifndef ESP8266
extern const char* getContentType(const String& path); extern const char* getContentType(const String& path);
#else #else
extern const __FlashStringHelper* getContentType(const String& path); extern const __FlashStringHelper* getContentType(const String& path);
#endif #endif
_contentType = getContentType(path); _contentType = getContentType(path);
#else #else