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
[![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/)
[![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)
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.
```
mathieucarbou/ESPAsyncWebServer @ 3.2.0
mathieucarbou/ESPAsyncWebServer @ 3.2.4
```
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))
- **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 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): 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): 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): 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

View File

@ -1,11 +1,13 @@
# 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/)
[![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)
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.
```
mathieucarbou/ESPAsyncWebServer @ 3.2.0
mathieucarbou/ESPAsyncWebServer @ 3.2.4
```
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))
- **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 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): 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): 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): 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

View File

@ -25,8 +25,40 @@
#include <LittleFS.h>
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) {
request->send(404, "text/plain", "Not found");
@ -73,8 +105,11 @@ void setup() {
server.on("/download", HTTP_HEAD | HTTP_GET, [](AsyncWebServerRequest* request) {
if (request->method() == HTTP_HEAD) {
AsyncWebServerResponse* response = request->beginResponse(200, "application/octet-stream");
response->setContentLength(1024); // myFile.getSize()
response->addHeader("Accept-Ranges", "bytes");
response->addHeader(asyncsrv::T_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);
} else {
@ -108,7 +143,7 @@ void setup() {
// receives JSON and sends JSON
jsonHandler->onRequest([](AsyncWebServerRequest* request, JsonVariant& json) {
JsonObject jsonObj = json.as<JsonObject>();
// JsonObject jsonObj = json.as<JsonObject>();
// ...
AsyncJsonResponse* response = new AsyncJsonResponse();
@ -131,7 +166,7 @@ void setup() {
// receives MessagePack and sends MessagePack
msgPackHandler->onRequest([](AsyncWebServerRequest* request, JsonVariant& json) {
JsonObject jsonObj = json.as<JsonObject>();
// JsonObject jsonObj = json.as<JsonObject>();
// ...
AsyncMessagePackResponse* response = new AsyncMessagePackResponse();
@ -150,6 +185,43 @@ void setup() {
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(msgPackHandler);
@ -158,5 +230,20 @@ void setup() {
server.begin();
}
uint32_t lastSSE = 0;
uint32_t deltaSSE = 5;
uint32_t lastWS = 0;
uint32_t deltaWS = 100;
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",
"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.",
"keywords": "http,async,websocket,webserver",
"homepage": "https://github.com/mathieucarbou/ESPAsyncWebServer",
@ -28,7 +28,7 @@
{
"owner": "mathieucarbou",
"name": "AsyncTCP",
"version": "^3.2.4",
"version": "^3.2.5",
"platforms": "espressif32"
},
{

View File

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

View File

@ -2,6 +2,7 @@
framework = arduino
build_flags =
-Wall -Wextra
-Wno-unused-parameter
-D CONFIG_ARDUHAL_LOG_COLORS
-D CORE_DEBUG_LEVEL=ARDUHAL_LOG_LEVEL_VERBOSE
-D CONFIG_ASYNC_TCP_MAX_ACK_TIME=3000
@ -22,19 +23,12 @@ src_dir = examples/SimpleServer
; src_dir = examples/Draft
; 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]
platform = espressif32@6.8.1
board = esp32dev
lib_deps =
bblanchon/ArduinoJson @ 7.1.0
mathieucarbou/AsyncTCP @ 3.2.4
mathieucarbou/AsyncTCP @ 3.2.5
[env:arduino-3]
platform = espressif32
@ -44,7 +38,7 @@ platform_packages=
board = esp32dev
lib_deps =
bblanchon/ArduinoJson @ 7.1.0
mathieucarbou/AsyncTCP @ 3.2.4
mathieucarbou/AsyncTCP @ 3.2.5
[env:esp8266]
platform = espressif8266
@ -70,18 +64,18 @@ platform = https://github.com/pioarduino/platform-espressif32/releases/download/
board = esp32dev
lib_deps =
bblanchon/ArduinoJson @ 7.1.0
mathieucarbou/AsyncTCP @ 3.2.4
mathieucarbou/AsyncTCP @ 3.2.5
[env:pioarduino-c6]
platform = https://github.com/pioarduino/platform-espressif32/releases/download/51.03.04/platform-espressif32.zip
board = esp32-c6-devkitc-1
lib_deps =
bblanchon/ArduinoJson @ 7.1.0
mathieucarbou/AsyncTCP @ 3.2.4
mathieucarbou/AsyncTCP @ 3.2.5
[env:pioarduino-h2]
platform = https://github.com/pioarduino/platform-espressif32/releases/download/51.03.04/platform-espressif32.zip
board = esp32-h2-devkitm-1
lib_deps =
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);
}
size_t AsyncEventSourceMessage::ack(size_t len, uint32_t time) {
(void)time;
size_t AsyncEventSourceMessage::ack(size_t len, __attribute__((unused)) uint32_t time) {
// If the whole message is now acked...
if (_acked + len > _len) {
// 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;
}
// This could also return void as the return value is not used.
// Leaving as-is for compatibility...
size_t AsyncEventSourceMessage::send(AsyncClient* client) {
if (_sent >= _len) {
size_t AsyncEventSourceMessage::write(AsyncClient* client) {
if (_sent >= _len || !client->canSend()) {
return 0;
}
const size_t len_to_send = _len - _sent;
auto position = reinterpret_cast<const char*>(_data + _sent);
const size_t sent_now = client->write(position, len_to_send);
_sent += sent_now;
return sent_now;
size_t len = min(_len - _sent, client->space());
size_t sent = client->add((const char*)_data + _sent, len);
_sent += sent;
return sent;
}
size_t AsyncEventSourceMessage::send(AsyncClient* client) {
size_t sent = write(client);
return sent && client->send() ? sent : 0;
}
// Client
@ -174,6 +175,8 @@ AsyncEventSourceClient::AsyncEventSourceClient(AsyncWebServerRequest* request, A
_server->_addClient(this);
delete request;
_client->setNoDelay(true);
}
AsyncEventSourceClient::~AsyncEventSourceClient() {
@ -211,11 +214,6 @@ void AsyncEventSourceClient::_onAck(size_t len, uint32_t time) {
// Same here, acquiring the lock early
std::lock_guard<std::mutex> lock(_lockmq);
#endif
while (len && _messageQueue.size()) {
len = _messageQueue.front().ack(len, time);
if (_messageQueue.front().finished())
_messageQueue.pop_front();
}
_runQueue();
}
@ -264,11 +262,24 @@ size_t AsyncEventSourceClient::packetsWaiting() const {
}
void AsyncEventSourceClient::_runQueue() {
// Calls to this private method now already protected by _lockmq acquisition
// so no extra call of _lockmq.lock() here..
for (auto& i : _messageQueue) {
if (!i.sent())
i.send(_client);
size_t total_bytes_written = 0;
for (auto i = _messageQueue.begin(); i != _messageQueue.end(); ++i) {
if (!i->sent()) {
const size_t bytes_written = i->write(_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) {
String out = _assembleHead(request->version());
String out;
_assembleHead(out, request->version());
request->client()->write(out.c_str(), _headLength);
_state = RESPONSE_WAIT_ACK;
}

View File

@ -49,14 +49,6 @@
#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 AsyncEventSourceResponse;
class AsyncEventSourceClient;
@ -74,7 +66,8 @@ class AsyncEventSourceMessage {
public:
AsyncEventSourceMessage(const char* data, size_t len);
~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);
bool finished() { return _acked == _len; }
bool sent() { return _sent == _len; }
@ -99,6 +92,8 @@ class AsyncEventSourceClient {
AsyncClient* client() { return _client; }
void close();
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);
bool connected() const { return (_client != NULL) && _client->connected(); }
uint32_t lastId() const { return _lastId; }
@ -131,6 +126,8 @@ class AsyncEventSource : public AsyncWebHandler {
void close();
void onConnect(ArEventHandlerFunction 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);
// number of clients connected
size_t count() const;

View File

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

View File

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

View File

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

View File

@ -45,10 +45,10 @@
#include "literals.h"
#define ASYNCWEBSERVER_VERSION "3.2.0"
#define ASYNCWEBSERVER_VERSION "3.2.4"
#define ASYNCWEBSERVER_VERSION_MAJOR 3
#define ASYNCWEBSERVER_VERSION_MINOR 2
#define ASYNCWEBSERVER_VERSION_REVISION 0
#define ASYNCWEBSERVER_VERSION_REVISION 4
#define ASYNCWEBSERVER_FORK_mathieucarbou
#ifdef ASYNCWEBSERVER_REGEX
@ -155,7 +155,9 @@ class AsyncWebHeader {
const String& name() const { return _name; }
const String& value() const { return _value; }
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)0x20);
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 String& contentType, AwsResponseFiller callback, AwsTemplateProcessor templateCallback = nullptr) { send(beginChunkedResponse(contentType, callback, templateCallback)); }
#ifndef ESP8266
[[deprecated("Replaced by send(...)")]]
#endif
void send_P(int code, const String& contentType, const uint8_t* content, size_t len, AwsTemplateProcessor callback = nullptr) {
send(code, contentType, content, len, callback);
}
#ifndef ESP8266
[[deprecated("Replaced by send(...)")]]
#endif
void send_P(int code, const String& contentType, PGM_P content, AwsTemplateProcessor callback = nullptr) {
send(code, contentType, content, callback);
}
@ -370,13 +376,17 @@ class AsyncWebServerRequest {
AsyncResponseStream* beginResponseStream(const char* contentType, size_t bufferSize = 1460);
AsyncResponseStream* beginResponseStream(const String& contentType, size_t bufferSize = 1460) { return beginResponseStream(contentType.c_str(), bufferSize); }
#ifndef ESP8266
[[deprecated("Replaced by beginResponse(...)")]]
#endif
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(...)")]]
#endif
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
@ -583,8 +593,21 @@ class AsyncWebServerResponse {
virtual void setContentType(const char* type);
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 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 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 _finished() 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 {
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);
}

View File

@ -126,8 +126,7 @@ const char* AsyncWebServerResponse::responseCodeToString(int code) {
}
}
#else // ESP8266
const __FlashStringHelper* AsyncWebServerResponse::responseCodeToString(int code)
{
const __FlashStringHelper* AsyncWebServerResponse::responseCodeToString(int code) {
switch (code) {
case 100:
return FPSTR(T_HTTP_CODE_100);
@ -230,12 +229,12 @@ void AsyncWebServerResponse::setCode(int code) {
}
void AsyncWebServerResponse::setContentLength(size_t len) {
if (_state == RESPONSE_SETUP)
if (_state == RESPONSE_SETUP && addHeader(T_Content_Length, len, true))
_contentLength = len;
}
void AsyncWebServerResponse::setContentType(const char* type) {
if (_state == RESPONSE_SETUP)
if (_state == RESPONSE_SETUP && addHeader(T_Content_Type, type, true))
_contentType = type;
}
@ -249,6 +248,11 @@ bool AsyncWebServerResponse::removeHeader(const char* name) {
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) {
for (auto i = _headers.begin(); i != _headers.end(); ++i) {
if (i->name().equalsIgnoreCase(name)) {
@ -268,41 +272,56 @@ bool AsyncWebServerResponse::addHeader(const char* name, const char* value, bool
return true;
}
String AsyncWebServerResponse::_assembleHead(uint8_t version) {
void AsyncWebServerResponse::_assembleHead(String& buffer, uint8_t version) {
if (version) {
addHeader(T_Accept_Ranges, T_none, false);
if (_chunked)
addHeader(T_Transfer_Encoding, T_chunked, false);
}
String out;
constexpr size_t bufSize = 300;
char buf[bufSize];
#ifndef ESP8266
snprintf(buf, bufSize, "HTTP/1.%d %d %s\r\n", version, _code, responseCodeToString(_code));
if (_sendContentLength)
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
snprintf_P(buf, bufSize, PSTR("HTTP/1.%d %d %s\r\n"), version, _code, String(responseCodeToString(_code)).c_str());
buffer.concat("HTTP/1.");
#endif
out.concat(buf);
if (_sendContentLength) {
snprintf_P(buf, bufSize, PSTR("Content-Length: %d\r\n"), _contentLength);
out.concat(buf);
}
if (_contentType.length()) {
snprintf_P(buf, bufSize, PSTR("Content-Type: %s\r\n"), _contentType.c_str());
out.concat(buf);
}
buffer.concat(version);
buffer.concat(' ');
buffer.concat(_code);
buffer.concat(' ');
buffer.concat(responseCodeToString(_code));
buffer.concat(T_rn);
// Add headers
for (const auto& header : _headers) {
snprintf_P(buf, bufSize, PSTR("%s: %s\r\n"), header.name().c_str(), header.value().c_str());
out.concat(buf);
buffer.concat(header.name());
#ifdef ESP8266
buffer.concat(PSTR(": "));
#else
buffer.concat(": ");
#endif
buffer.concat(header.value());
buffer.concat(T_rn);
}
_headers.clear();
out.concat(T_rn);
_headLength = out.length();
return out;
buffer.concat(T_rn);
_headLength = buffer.length();
}
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) {
_state = RESPONSE_HEADERS;
String out = _assembleHead(request->version());
String out;
_assembleHead(out, request->version());
size_t outLen = out.length();
size_t space = request->client()->space();
if (!_contentLength && space >= outLen) {
@ -411,7 +431,7 @@ AsyncAbstractResponse::AsyncAbstractResponse(AwsTemplateProcessor callback) : _c
void AsyncAbstractResponse::_respond(AsyncWebServerRequest* request) {
addHeader(T_Connection, T_close, false);
_head = _assembleHead(request->version());
_assembleHead(_head, request->version());
_state = RESPONSE_HEADERS;
_ack(request, 0, 0);
}
@ -472,9 +492,7 @@ size_t AsyncAbstractResponse::_ack(AsyncWebServerRequest* request, size_t len, u
free(buf);
return 0;
}
outLen = sprintf_P((char*)buf + headLen, PSTR("%x"), readLen) + headLen;
while (outLen < headLen + 4)
buf[outLen++] = ' ';
outLen = sprintf((char*)buf+headLen, "%04x", readLen) + headLen;
buf[outLen++] = '\r';
buf[outLen++] = '\n';
outLen += readLen;