Update to 3.10.3

This commit is contained in:
2026-04-01 08:50:55 +02:00
parent f5e5d92d31
commit 1d45d307ab
35 changed files with 723 additions and 229 deletions
+1 -1
View File
@@ -60,7 +60,7 @@ body:
id: stack-trace
attributes:
label: Stack Trace
description: Please provide a debug message or error message. If you have a Guru Meditation Error or Backtrace, [please decode it](https://maximeborges.github.io/esp-stacktrace-decoder/).
description: Please provide a debug message or error message. If you have a Guru Meditation Error or Backtrace, [please decode it](https://esphome.github.io/esp-stacktrace-decoder/).
placeholder: For Arduino IDE, Enable Core debug level - Debug on tools menu, then put the serial output here.
validations:
required: true
+1 -1
View File
@@ -27,7 +27,7 @@ jobs:
name: Arduino Lint
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v6
- uses: arduino/arduino-lint-action@v2
with:
library-manager: update
+5 -5
View File
@@ -43,7 +43,7 @@ jobs:
run: ARDUINO_LIBRARY_ENABLE_UNSAFE_INSTALL=true arduino-cli lib install --git-url https://github.com/ESP32Async/AsyncTCP#v3.4.10
- name: Checkout
uses: actions/checkout@v5
uses: actions/checkout@v6
- name: Build Examples
run: |
@@ -74,7 +74,7 @@ jobs:
run: ARDUINO_LIBRARY_ENABLE_UNSAFE_INSTALL=true arduino-cli lib install --git-url https://github.com/ESP32Async/AsyncTCP#v3.4.10
- name: Checkout
uses: actions/checkout@v5
uses: actions/checkout@v6
- name: Build Examples
run: |
@@ -99,7 +99,7 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v5
uses: actions/checkout@v6
- name: Python
uses: actions/setup-python@v6
with:
@@ -139,7 +139,7 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v5
uses: actions/checkout@v6
- name: Python
uses: actions/setup-python@v6
with:
@@ -178,7 +178,7 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v5
uses: actions/checkout@v6
- name: Python
uses: actions/setup-python@v6
with:
+2 -2
View File
@@ -43,7 +43,7 @@ jobs:
run: ARDUINO_LIBRARY_ENABLE_UNSAFE_INSTALL=true arduino-cli lib install --git-url https://github.com/ESP32Async/ESPAsyncTCP#v2.0.0
- name: Checkout
uses: actions/checkout@v5
uses: actions/checkout@v6
- name: Build Examples
run: |
@@ -66,7 +66,7 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v5
uses: actions/checkout@v6
- name: Python
uses: actions/setup-python@v6
with:
+1 -1
View File
@@ -35,7 +35,7 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v5
uses: actions/checkout@v6
- name: Python
uses: actions/setup-python@v6
with:
+2 -2
View File
@@ -50,7 +50,7 @@ jobs:
run: ARDUINO_LIBRARY_ENABLE_UNSAFE_INSTALL=true arduino-cli lib install --git-url https://github.com/ayushsharma82/RPAsyncTCP#v1.3.2
- name: Checkout
uses: actions/checkout@v5
uses: actions/checkout@v6
- name: Build Examples
run: |
@@ -73,7 +73,7 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v5
uses: actions/checkout@v6
- name: Python
uses: actions/setup-python@v6
with:
+2 -2
View File
@@ -28,10 +28,10 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v5
uses: actions/checkout@v6
- name: Cache
uses: actions/cache@v4
uses: actions/cache@v5
with:
key: ${{ runner.os }}-cpplint
path: ~/.cache/pip
+1 -1
View File
@@ -23,7 +23,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout latest commit
uses: actions/checkout@v5
uses: actions/checkout@v6
with:
fetch-depth: 2
+2 -2
View File
@@ -16,7 +16,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v5
uses: actions/checkout@v6
with:
fetch-tags: true
fetch-depth: 0 # Ensure all commits and tags are fetched
@@ -39,7 +39,7 @@ jobs:
curl -L -o project.zip "https://github.com/${{ github.repository }}/archive/refs/tags/$TAG_NAME.zip"
# - name: Cache PlatformIO
# uses: actions/cache@v4
# uses: actions/cache@v5
# with:
# key: ${{ runner.os }}-pio
# path: |
+1 -1
View File
@@ -36,7 +36,7 @@ jobs:
echo "Tag: $tag"
echo "RELEASE_TAG=$tag" >> $GITHUB_ENV
- uses: actions/checkout@v5
- uses: actions/checkout@v6
with:
ref: ${{ inputs.git_ref || env.RELEASE_TAG }}
submodules: "recursive"
+2 -2
View File
@@ -12,8 +12,8 @@ jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
- uses: actions/checkout@v6
- uses: actions/setup-python@v6
with:
python-version: 3.x
- run: pip install mkdocs-material
+5 -5
View File
@@ -1887,7 +1887,7 @@ void setup(){
}, onUpload);
// send a file when /index is requested
server.on("/index", HTTP_ANY, [](AsyncWebServerRequest *request){
server.on("/index", HTTP_ALL, [](AsyncWebServerRequest *request){
request->send(SPIFFS, "/index.htm");
});
@@ -1974,10 +1974,10 @@ public :
void begin(){
// attach global request handler
classWebServer.on("/example", HTTP_ANY, handleRequest);
classWebServer.on("/example", HTTP_ALL, handleRequest);
// attach class request handler
classWebServer.on("/example", HTTP_ANY, std::bind(&WebClass::classRequest, this, std::placeholders::_1));
classWebServer.on("/example", HTTP_ALL, std::bind(&WebClass::classRequest, this, std::placeholders::_1));
}
};
@@ -1986,10 +1986,10 @@ WebClass webClassInstance;
void setup() {
// attach global request handler
globalWebServer.on("/example", HTTP_ANY, handleRequest);
globalWebServer.on("/example", HTTP_ALL, handleRequest);
// attach class request handler
globalWebServer.on("/example", HTTP_ANY, std::bind(&WebClass::classRequest, webClassInstance, std::placeholders::_1));
globalWebServer.on("/example", HTTP_ALL, std::bind(&WebClass::classRequest, webClassInstance, std::placeholders::_1));
}
void loop() {
+6 -6
View File
@@ -71,12 +71,12 @@ void setup(){
}, onUpload);
// send a file when /index is requested (SPIFFS example)
server.on("/index", HTTP_ANY, [](AsyncWebServerRequest *request){
server.on("/index", HTTP_ALL, [](AsyncWebServerRequest *request){
request->send(SPIFFS, "/index.htm");
});
// send a file when /index is requested (LittleFS example)
server.on("/index", HTTP_ANY, [](AsyncWebServerRequest *request){
server.on("/index", HTTP_ALL, [](AsyncWebServerRequest *request){
request->send(LittleFS, "/index.htm");
});
@@ -161,10 +161,10 @@ public :
void begin(){
// attach global request handler
classWebServer.on("/example", HTTP_ANY, handleRequest);
classWebServer.on("/example", HTTP_ALL, handleRequest);
// attach class request handler
classWebServer.on("/example", HTTP_ANY, std::bind(&WebClass::classRequest, this, std::placeholders::_1));
classWebServer.on("/example", HTTP_ALL, std::bind(&WebClass::classRequest, this, std::placeholders::_1));
}
};
@@ -173,10 +173,10 @@ WebClass webClassInstance;
void setup() {
// attach global request handler
globalWebServer.on("/example", HTTP_ANY, handleRequest);
globalWebServer.on("/example", HTTP_ALL, handleRequest);
// attach class request handler
globalWebServer.on("/example", HTTP_ANY, std::bind(&WebClass::classRequest, webClassInstance, std::placeholders::_1));
globalWebServer.on("/example", HTTP_ALL, std::bind(&WebClass::classRequest, webClassInstance, std::placeholders::_1));
}
void loop() {
@@ -0,0 +1,124 @@
// SPDX-License-Identifier: LGPL-3.0-or-later
// Copyright 2016-2026 Hristo Gochkov, Mathieu Carbou, Emil Muratov, Will Miles
//
// HTTP Method usage example and check compatibility with Arduino HTTP Methods when HTTP_Method.h is included.
// ESP-IDf enums are imported, and HTTP_ANY is defined by Arduino Core.
// In that case, we cannot use directly asyncws enums: we have to namespace them.
// Also, asycnws HTTP_ANY is not available sine already defined by Arduino as a macro.
// So we have to use AsyncWebRequestMethod::HTTP_ALL instead of HTTP_ANY in that case.
//
#include <Arduino.h>
#if !defined(ESP8266)
#include <HTTP_Method.h>
#endif
#if defined(ESP32) || defined(LIBRETINY)
#include <AsyncTCP.h>
#include <WiFi.h>
#elif defined(ESP8266)
#include <ESP8266WiFi.h>
#include <ESPAsyncTCP.h>
#elif defined(TARGET_RP2040) || defined(TARGET_RP2350) || defined(PICO_RP2040) || defined(PICO_RP2350)
#include <RPAsyncTCP.h>
#include <WiFi.h>
#endif
#include <ESPAsyncWebServer.h>
static AsyncWebServer server(80);
#if ASYNC_JSON_SUPPORT == 1
// https://github.com/ESP32Async/ESPAsyncWebServer/issues/404
static void handlePostTest(AsyncWebServerRequest *req, JsonVariant &json) {
AsyncWebServerResponse *response;
if (req->method() == WebRequestMethod::HTTP_POST) {
response = req->beginResponse(200, "application/json", "{\"msg\": \"OK\"}");
} else {
response = req->beginResponse(501, "application/json", "{\"msg\": \"Not Implemented\"}");
}
req->send(response);
}
#endif
// user defined functions that turns out to have similar signatures to the ones in global header
int stringToMethod(const String &) {
return 0;
}
const char *methodToString(WebRequestMethod) {
return "METHOD";
}
bool methodMatches(WebRequestMethodComposite c, WebRequestMethod m) {
return false;
};
static WebRequestMethodComposite allowed = AsyncWebRequestMethod::HTTP_HEAD | AsyncWebRequestMethod::HTTP_OPTIONS;
class MyRequestHandler : public AsyncWebHandler {
public:
bool canHandle(__unused AsyncWebServerRequest *request) const override {
// Test backward compatibility with previous way of checking if a method is allowed in a composite using a bit operator
return allowed & request->method();
}
void handleRequest(AsyncWebServerRequest *request) override {
request->send(200, "text/plain", "Hello from custom handler");
}
};
void setup() {
Serial.begin(115200);
#if ASYNCWEBSERVER_WIFI_SUPPORTED
WiFi.mode(WIFI_AP);
WiFi.softAP("esp-captive");
#endif
// curl -v http://192.168.4.1/get-or-post
// curl -v -X POST -d "a=b" http://192.168.4.1/get-or-post
server.on("/get-or-post", AsyncWebRequestMethod::HTTP_GET | AsyncWebRequestMethod::HTTP_POST, [](AsyncWebServerRequest *request) {
request->send(200, "text/plain", "Hello");
});
// curl -v http://192.168.4.1/all
server.on("/all", AsyncWebRequestMethod::HTTP_ALL, [](AsyncWebServerRequest *request) {
request->send(200, "text/plain", "Hello");
});
#if ASYNC_JSON_SUPPORT == 1
// curl -v http://192.168.4.1/test => Not Implemented
// curl -v -X POST -H 'Content-Type: application/json' -d '{"name":"You"}' http://192.168.4.1/test => OK
AsyncCallbackJsonWebHandler *testHandler = new AsyncCallbackJsonWebHandler("/test", handlePostTest);
server.addHandler(testHandler);
#endif
// curl -v -X HEAD http://192.168.4.1/custom => answers
// curl -v -X OPTIONS http://192.168.4.1/custom => answers
// curl -v -X POST http://192.168.4.1/custom => no answer
server.addHandler(new MyRequestHandler());
server.begin();
WebRequestMethodComposite composite1 = AsyncWebRequestMethod::HTTP_GET | AsyncWebRequestMethod::HTTP_POST;
WebRequestMethodComposite composite2 = AsyncWebRequestMethod::HTTP_GET | AsyncWebRequestMethod::HTTP_POST;
WebRequestMethodComposite composite3 = AsyncWebRequestMethod::HTTP_HEAD | AsyncWebRequestMethod::HTTP_OPTIONS;
WebRequestMethodComposite composite4 = composite3;
WebRequestMethodComposite composite5 = AsyncWebRequestMethod::HTTP_GET;
assert(composite1.matches(AsyncWebRequestMethod::HTTP_GET));
assert(composite1.matches(AsyncWebRequestMethod::HTTP_POST));
assert(!composite1.matches(AsyncWebRequestMethod::HTTP_HEAD));
assert(!composite3.matches(AsyncWebRequestMethod::HTTP_GET));
assert(composite1 == composite2);
assert(composite3 == composite4);
assert(composite1 != composite3);
assert(composite5 == AsyncWebRequestMethod::HTTP_GET);
}
// not needed
void loop() {
delay(100);
}
@@ -0,0 +1,127 @@
// SPDX-License-Identifier: LGPL-3.0-or-later
// Copyright 2016-2026 Hristo Gochkov, Mathieu Carbou, Emil Muratov, Will Miles
//
// HTTP Method usage example and check compatibility with ESP-IDF HTTP Methods when http_parser.h is included.
// ESP-IDF enums are imported, and HTTP_ANY is NOT defined by ESP-IDF.
// So asyncws is able to define it.
// We cannot use directly other asyncws enums to avoid conflicts with ESP-IDF: we have to namespace them.
//
#include <Arduino.h>
#if !defined(ESP8266)
#include "http_parser.h"
#endif
#if defined(ESP32) || defined(LIBRETINY)
#include <AsyncTCP.h>
#include <WiFi.h>
#elif defined(ESP8266)
#include <ESP8266WiFi.h>
#include <ESPAsyncTCP.h>
#elif defined(TARGET_RP2040) || defined(TARGET_RP2350) || defined(PICO_RP2040) || defined(PICO_RP2350)
#include <RPAsyncTCP.h>
#include <WiFi.h>
#endif
#include <ESPAsyncWebServer.h>
static AsyncWebServer server(80);
#if ASYNC_JSON_SUPPORT == 1
// https://github.com/ESP32Async/ESPAsyncWebServer/issues/404
static void handlePostTest(AsyncWebServerRequest *req, JsonVariant &json) {
AsyncWebServerResponse *response;
if (req->method() == WebRequestMethod::HTTP_POST) {
response = req->beginResponse(200, "application/json", "{\"msg\": \"OK\"}");
} else {
response = req->beginResponse(501, "application/json", "{\"msg\": \"Not Implemented\"}");
}
req->send(response);
}
#endif
// user defined functions that turns out to have similar signatures to the ones in global header
int stringToMethod(const String &) {
return 0;
}
const char *methodToString(WebRequestMethod) {
return "METHOD";
}
bool methodMatches(WebRequestMethodComposite c, WebRequestMethod m) {
return false;
};
static WebRequestMethodComposite allowed = AsyncWebRequestMethod::HTTP_HEAD | AsyncWebRequestMethod::HTTP_OPTIONS;
class MyRequestHandler : public AsyncWebHandler {
public:
bool canHandle(__unused AsyncWebServerRequest *request) const override {
// Test backward compatibility with previous way of checking if a method is allowed in a composite using a bit operator
return allowed & request->method();
}
void handleRequest(AsyncWebServerRequest *request) override {
request->send(200, "text/plain", "Hello from custom handler");
}
};
void setup() {
Serial.begin(115200);
#if ASYNCWEBSERVER_WIFI_SUPPORTED
WiFi.mode(WIFI_AP);
WiFi.softAP("esp-captive");
#endif
// curl -v http://192.168.4.1/get-or-post
// curl -v -X POST -d "a=b" http://192.168.4.1/get-or-post
server.on("/get-or-post", AsyncWebRequestMethod::HTTP_GET | AsyncWebRequestMethod::HTTP_POST, [](AsyncWebServerRequest *request) {
request->send(200, "text/plain", "Hello");
});
// curl -v http://192.168.4.1/all
server.on("/all", AsyncWebRequestMethod::HTTP_ALL, [](AsyncWebServerRequest *request) {
request->send(200, "text/plain", "Hello");
});
server.on("/any", AsyncWebRequestMethod::HTTP_ANY, [](AsyncWebServerRequest *request) {
request->send(200, "text/plain", "Hello");
});
#if ASYNC_JSON_SUPPORT == 1
// curl -v http://192.168.4.1/test => Not Implemented
// curl -v -X POST -H 'Content-Type: application/json' -d '{"name":"You"}' http://192.168.4.1/test => OK
AsyncCallbackJsonWebHandler *testHandler = new AsyncCallbackJsonWebHandler("/test", handlePostTest);
server.addHandler(testHandler);
#endif
// curl -v -X HEAD http://192.168.4.1/custom => answers
// curl -v -X OPTIONS http://192.168.4.1/custom => answers
// curl -v -X POST http://192.168.4.1/custom => no answer
server.addHandler(new MyRequestHandler());
server.begin();
WebRequestMethodComposite composite1 = AsyncWebRequestMethod::HTTP_GET | AsyncWebRequestMethod::HTTP_POST;
WebRequestMethodComposite composite2 = AsyncWebRequestMethod::HTTP_GET | AsyncWebRequestMethod::HTTP_POST;
WebRequestMethodComposite composite3 = AsyncWebRequestMethod::HTTP_HEAD | AsyncWebRequestMethod::HTTP_OPTIONS;
WebRequestMethodComposite composite4 = composite3;
WebRequestMethodComposite composite5 = AsyncWebRequestMethod::HTTP_GET;
assert(composite1.matches(AsyncWebRequestMethod::HTTP_GET));
assert(composite1.matches(AsyncWebRequestMethod::HTTP_POST));
assert(!composite1.matches(AsyncWebRequestMethod::HTTP_HEAD));
assert(!composite3.matches(AsyncWebRequestMethod::HTTP_GET));
assert(composite1 == composite2);
assert(composite3 == composite4);
assert(composite1 != composite3);
assert(composite5 == AsyncWebRequestMethod::HTTP_GET);
}
// not needed
void loop() {
delay(100);
}
+2
View File
@@ -118,6 +118,8 @@ void setup() {
if (info->message_opcode == WS_TEXT) {
Serial.printf("ws text: %s\n", (char *)data);
client->ping();
// Also send a message in the message queue when we get one
ws.textAll("Message received: " + String((char *)data));
}
} else {
+1 -1
View File
@@ -32,7 +32,7 @@ dependencies:
version: "^3.4.10"
require: public
bblanchon/arduinojson:
version: "^7.4.2"
version: "^7.4.3"
require: public
examples:
- path: ./idf_component_examples/catchall
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "ESPAsyncWebServer",
"version": "3.10.0",
"version": "3.10.3",
"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/ESP32Async/ESPAsyncWebServer",
+1 -1
View File
@@ -1,6 +1,6 @@
name=ESP Async WebServer
includes=ESPAsyncWebServer.h
version=3.10.0
version=3.10.3
author=ESP32Async
maintainer=ESP32Async
sentence=Asynchronous HTTP and WebSocket Server Library for ESP32, ESP8266 and RP2040
@@ -18,7 +18,7 @@ lib_compat_mode = strict
lib_ldf_mode = chain
lib_deps =
ESP32Async/AsyncTCP @ 3.4.10
ESP32Async/ESpAsyncWebServer @ 3.9.6
ESP32Async/ESpAsyncWebServer @ 3.10.2
custom_component_remove =
espressif/esp_hosted
espressif/esp_wifi_remote
+7 -4
View File
@@ -14,6 +14,9 @@ lib_dir = .
; src_dir = examples/Filters
; src_dir = examples/FlashResponse
; src_dir = examples/HeaderManipulation
; src_dir = examples/Headers
; src_dir = examples/HTTPMethodsWithArduino
; src_dir = examples/HTTPMethodsWithESPIDF
; src_dir = examples/Json
; src_dir = examples/LargeResponse
; src_dir = examples/Logging
@@ -38,9 +41,9 @@ src_dir = examples/PerfTests
; src_dir = examples/UploadFlash
; src_dir = examples/URIMatcher
; src_dir = examples/URIMatcherTest
; src_dir = examples/WebDAVMethods
; src_dir = examples/WebSocket
; src_dir = examples/WebSocketEasy
; src_dir = examples/WebDAVMethods
[env]
framework = arduino
@@ -72,7 +75,7 @@ monitor_filters = esp32_exception_decoder, log2file
lib_compat_mode = strict
lib_ldf_mode = chain
lib_deps =
bblanchon/ArduinoJson @ 7.4.2
bblanchon/ArduinoJson @ 7.4.3
; bblanchon/ArduinoJson @ 6.21.5
; bblanchon/ArduinoJson @ 5.13.4
ESP32Async/AsyncTCP @ 3.4.10
@@ -93,7 +96,7 @@ platform = espressif8266
; board = huzzah
board = d1_mini
lib_deps =
bblanchon/ArduinoJson @ 7.4.2
bblanchon/ArduinoJson @ 7.4.3
ESP32Async/ESPAsyncTCP @ 2.0.0
[env:raspberrypi]
@@ -167,7 +170,7 @@ board = ${sysenv.PIO_BOARD}
platform = espressif8266
board = ${sysenv.PIO_BOARD}
lib_deps =
bblanchon/ArduinoJson @ 7.4.2
bblanchon/ArduinoJson @ 7.4.3
ESP32Async/ESPAsyncTCP @ 2.0.0
[env:ci-raspberrypi]
+23 -19
View File
@@ -192,6 +192,7 @@ AsyncEventSourceClient::AsyncEventSourceClient(AsyncWebServerRequest *request, A
AsyncEventSourceClient::~AsyncEventSourceClient() {
#ifdef ESP32
// Protect message queue access (size checks and modifications) which is not thread-safe.
std::lock_guard<std::recursive_mutex> lock(_lockmq);
#endif
_messageQueue.clear();
@@ -199,16 +200,16 @@ AsyncEventSourceClient::~AsyncEventSourceClient() {
}
bool AsyncEventSourceClient::_queueMessage(const char *message, size_t len) {
if (_messageQueue.size() >= SSE_MAX_QUEUED_MESSAGES) {
async_ws_log_e("Event message queue overflow: discard message");
return false;
}
#ifdef ESP32
// length() is not thread-safe, thus acquiring the lock before this call..
// Protect message queue access (size checks and modifications) which is not thread-safe.
std::lock_guard<std::recursive_mutex> lock(_lockmq);
#endif
if (_messageQueue.size() >= SSE_MAX_QUEUED_MESSAGES) {
async_ws_log_w("Event message queue overflow: discard message");
return false;
}
if (_client) {
_messageQueue.emplace_back(message, len);
} else {
@@ -230,16 +231,16 @@ bool AsyncEventSourceClient::_queueMessage(const char *message, size_t len) {
}
bool AsyncEventSourceClient::_queueMessage(AsyncEvent_SharedData_t &&msg) {
if (_messageQueue.size() >= SSE_MAX_QUEUED_MESSAGES) {
async_ws_log_e("Event message queue overflow: discard message");
return false;
}
#ifdef ESP32
// length() is not thread-safe, thus acquiring the lock before this call..
// Protect message queue access (size checks and modifications) which is not thread-safe.
std::lock_guard<std::recursive_mutex> lock(_lockmq);
#endif
if (_messageQueue.size() >= SSE_MAX_QUEUED_MESSAGES) {
async_ws_log_w("Event message queue overflow: discard message");
return false;
}
if (_client) {
_messageQueue.emplace_back(std::move(msg));
} else {
@@ -261,7 +262,7 @@ bool AsyncEventSourceClient::_queueMessage(AsyncEvent_SharedData_t &&msg) {
void AsyncEventSourceClient::_onAck(size_t len __attribute__((unused)), uint32_t time __attribute__((unused))) {
#ifdef ESP32
// Same here, acquiring the lock early
// Protect message queue access (size checks and modifications) which is not thread-safe.
std::lock_guard<std::recursive_mutex> lock(_lockmq);
#endif
@@ -288,11 +289,11 @@ void AsyncEventSourceClient::_onAck(size_t len __attribute__((unused)), uint32_t
}
void AsyncEventSourceClient::_onPoll() {
if (_messageQueue.size()) {
#ifdef ESP32
// Same here, acquiring the lock early
// Protect message queue access (size checks and modifications) which is not thread-safe.
std::lock_guard<std::recursive_mutex> lock(_lockmq);
#endif
if (_messageQueue.size()) {
_runQueue();
}
}
@@ -367,14 +368,17 @@ void AsyncEventSource::_addClient(AsyncEventSourceClient *client) {
if (!client) {
return;
}
#ifdef ESP32
std::lock_guard<std::recursive_mutex> lock(_client_queue_lock);
#endif
_clients.emplace_back(client);
if (_connectcb) {
_connectcb(client);
}
#ifdef ESP32
std::lock_guard<std::recursive_mutex> lock(_client_queue_lock);
#endif
_clients.emplace_back(client);
_adjust_inflight_window();
}
+3
View File
@@ -205,6 +205,9 @@ public:
return _lastId;
}
size_t packetsWaiting() const {
#ifdef ESP32
std::lock_guard<std::recursive_mutex> lock(_lockmq);
#endif
return _messageQueue.size();
};
+14 -9
View File
@@ -112,18 +112,23 @@ size_t AsyncMessagePackResponse::_fillBuffer(uint8_t *data, size_t len) {
#endif
// Body handler supporting both content types: JSON and MessagePack
constexpr static WebRequestMethodComposite JsonHandlerMethods =
AsyncWebRequestMethod::HTTP_GET | AsyncWebRequestMethod::HTTP_POST | AsyncWebRequestMethod::HTTP_PUT | AsyncWebRequestMethod::HTTP_PATCH;
#if ARDUINOJSON_VERSION_MAJOR == 6
AsyncCallbackJsonWebHandler::AsyncCallbackJsonWebHandler(AsyncURIMatcher uri, ArJsonRequestHandlerFunction onRequest, size_t maxJsonBufferSize)
: _uri(std::move(uri)), _method(HTTP_GET | HTTP_POST | HTTP_PUT | HTTP_PATCH), _onRequest(onRequest), maxJsonBufferSize(maxJsonBufferSize),
_maxContentLength(16384) {}
: _uri(std::move(uri)),
_method(AsyncWebRequestMethod::HTTP_GET | AsyncWebRequestMethod::HTTP_POST | AsyncWebRequestMethod::HTTP_PUT | AsyncWebRequestMethod::HTTP_PATCH),
_onRequest(onRequest), maxJsonBufferSize(maxJsonBufferSize), _maxContentLength(16384) {}
#else
AsyncCallbackJsonWebHandler::AsyncCallbackJsonWebHandler(AsyncURIMatcher uri, ArJsonRequestHandlerFunction onRequest)
: _uri(std::move(uri)), _method(HTTP_GET | HTTP_POST | HTTP_PUT | HTTP_PATCH), _onRequest(onRequest), _maxContentLength(16384) {}
: _uri(std::move(uri)),
_method(AsyncWebRequestMethod::HTTP_GET | AsyncWebRequestMethod::HTTP_POST | AsyncWebRequestMethod::HTTP_PUT | AsyncWebRequestMethod::HTTP_PATCH),
_onRequest(onRequest), _maxContentLength(16384) {}
#endif
bool AsyncCallbackJsonWebHandler::canHandle(AsyncWebServerRequest *request) const {
if (!_onRequest || !request->isHTTP() || !(_method & request->method())) {
if (!_onRequest || !request->isHTTP() || !_method.matches(request->method())) {
return false;
}
@@ -132,17 +137,17 @@ bool AsyncCallbackJsonWebHandler::canHandle(AsyncWebServerRequest *request) cons
}
#if ASYNC_MSG_PACK_SUPPORT == 1
return request->method() == HTTP_GET || request->contentType().equalsIgnoreCase(asyncsrv::T_application_json)
return request->method() == AsyncWebRequestMethod::HTTP_GET || request->contentType().equalsIgnoreCase(asyncsrv::T_application_json)
|| request->contentType().equalsIgnoreCase(asyncsrv::T_application_msgpack);
#else
return request->method() == HTTP_GET || request->contentType().equalsIgnoreCase(asyncsrv::T_application_json);
return request->method() == AsyncWebRequestMethod::HTTP_GET || request->contentType().equalsIgnoreCase(asyncsrv::T_application_json);
#endif
}
void AsyncCallbackJsonWebHandler::handleRequest(AsyncWebServerRequest *request) {
if (_onRequest) {
// GET request:
if (request->method() == HTTP_GET) {
if (request->method() == AsyncWebRequestMethod::HTTP_GET) {
JsonVariant json;
_onRequest(request, json);
return;
@@ -151,7 +156,7 @@ void AsyncCallbackJsonWebHandler::handleRequest(AsyncWebServerRequest *request)
// POST / PUT / ... requests:
// check if JSON body is too large, if it is, don't deserialize
if (request->contentLength() > _maxContentLength) {
async_ws_log_e("Content length exceeds maximum allowed");
async_ws_log_w("Content length exceeds maximum allowed");
request->send(413);
return;
}
@@ -206,7 +211,7 @@ void AsyncCallbackJsonWebHandler::handleBody(AsyncWebServerRequest *request, uin
// no way to know the actual length in advance. The best
// way to handle this would be to use a String instead of
// a fixed-length buffer, but for now we just reject.
async_ws_log_e("AsyncJson cannot handle chunked requests without X-Expected-Entity-Length");
async_ws_log_w("AsyncJson cannot handle chunked requests without X-Expected-Entity-Length");
request->abort();
return;
}
+3 -1
View File
@@ -6,6 +6,8 @@
#include <ESPAsyncWebServer.h>
#include "ChunkPrint.h"
#include <utility>
#if ASYNC_JSON_SUPPORT == 1
#if ARDUINOJSON_VERSION_MAJOR == 6
@@ -104,7 +106,7 @@ public:
#endif
void setMethod(WebRequestMethodComposite method) {
_method = method;
_method = std::move(method);
}
void setMaxContentLength(int maxContentLength) {
_maxContentLength = maxContentLength;
+1 -1
View File
@@ -12,7 +12,7 @@ extern "C" {
/** Minor version number (x.X.x) */
#define ASYNCWEBSERVER_VERSION_MINOR 10
/** Patch version number (x.x.X) */
#define ASYNCWEBSERVER_VERSION_PATCH 0
#define ASYNCWEBSERVER_VERSION_PATCH 3
/**
* Macro to convert version number into an integer
+84 -33
View File
@@ -171,8 +171,9 @@ size_t AsyncWebSocketMessage::ack(size_t len, uint32_t time) {
if (_sent >= _WSbuffer->size() && _acked >= _ack) {
_status = WS_MSG_SENT;
}
async_ws_log_v("opcode: %" PRIu8 ", acked: %u/%u, left: %u/%u, status: %d", _opcode, _acked, _ack, len - pending, len, static_cast<int>(_status));
return len - pending;
const size_t remaining = len - pending;
async_ws_log_v("ACK[%" PRIu8 "] %u/%u (acked: %u/%u) => %" PRIu8, _opcode, _sent, _WSbuffer->size(), _acked, _ack, static_cast<uint8_t>(_status));
return remaining;
}
size_t AsyncWebSocketMessage::send(AsyncClient *client) {
@@ -182,7 +183,7 @@ size_t AsyncWebSocketMessage::send(AsyncClient *client) {
}
if (_status != WS_MSG_SENDING) {
async_ws_log_v("C[%" PRIu16 "] Wrong status: got: %d, expected: %d", client->remotePort(), static_cast<int>(_status), static_cast<int>(WS_MSG_SENDING));
async_ws_log_v("SEND[%" PRIu8 "] => [%" PRIu16 "] WS_MSG_SENDING != %" PRIu8, _opcode, client->remotePort(), static_cast<uint8_t>(_status));
return 0;
}
@@ -190,12 +191,14 @@ size_t AsyncWebSocketMessage::send(AsyncClient *client) {
if (_acked == _ack) {
_status = WS_MSG_SENT;
}
async_ws_log_v("C[%" PRIu16 "] Already sent: %u/%u", client->remotePort(), _sent, _WSbuffer->size());
async_ws_log_v("SEND[%" PRIu8 "] => [%" PRIu16 "] WS_MSG_SENT %u/%u (acked: %u/%u)", _opcode, client->remotePort(), _sent, _WSbuffer->size(), _acked, _ack);
return 0;
}
if (_sent > _WSbuffer->size()) {
_status = WS_MSG_ERROR;
async_ws_log_v("C[%" PRIu16 "] Error, sent more: %u/%u", client->remotePort(), _sent, _WSbuffer->size());
async_ws_log_v(
"SEND[%" PRIu8 "] => [%" PRIu16 "] WS_MSG_ERROR %u/%u (acked: %u/%u)", _opcode, client->remotePort(), _sent, _WSbuffer->size(), _acked, _ack
);
return 0;
}
@@ -204,7 +207,7 @@ size_t AsyncWebSocketMessage::send(AsyncClient *client) {
// not enough space in lwip buffer ?
if (!window) {
async_ws_log_v("C[%" PRIu16 "] No space left to send more data: acked: %u, sent: %u, remaining: %u", client->remotePort(), _acked, _sent, toSend);
async_ws_log_v("SEND[%" PRIu8 "] => [%" PRIu16 "] NO_SPACE %u", _opcode, client->remotePort(), toSend);
return 0;
}
@@ -224,7 +227,9 @@ size_t AsyncWebSocketMessage::send(AsyncClient *client) {
_ack -= (toSend - sent);
}
async_ws_log_v("C[%" PRIu16 "] sent: %u/%u, final: %d, acked: %u/%u", client->remotePort(), _sent, _WSbuffer->size(), final, _acked, _ack);
async_ws_log_v(
"SEND[%" PRIu8 "] => [%" PRIu16 "] WS_MSG_SENDING %u/%u (acked: %u/%u)", _opcode, client->remotePort(), _sent, _WSbuffer->size(), _acked, _ack
);
return sent;
}
@@ -308,6 +313,8 @@ void AsyncWebSocketClient::_onAck(size_t len, uint32_t time) {
std::unique_lock<std::recursive_mutex> lock(_lock);
#endif
async_ws_log_v("[%s][%" PRIu32 "] START ACK(%u, %" PRIu32 ") Q:%u", _server->url(), _clientId, len, time, _messageQueue.size());
if (!_controlQueue.empty()) {
auto &head = _controlQueue.front();
if (head.finished()) {
@@ -315,6 +322,7 @@ void AsyncWebSocketClient::_onAck(size_t len, uint32_t time) {
if (_status == WS_DISCONNECTING && head.opcode() == WS_DISCONNECT) {
_controlQueue.pop_front();
_status = WS_DISCONNECTED;
async_ws_log_v("[%s][%" PRIu32 "] ACK WS_DISCONNECTED", _server->url(), _clientId);
if (_client) {
#ifdef ESP32
/*
@@ -343,6 +351,8 @@ void AsyncWebSocketClient::_onAck(size_t len, uint32_t time) {
_clearQueue();
async_ws_log_v("[%s][%" PRIu32 "] END ACK(%u, %" PRIu32 ") Q:%u", _server->url(), _clientId, len, time, _messageQueue.size());
_runQueue();
}
@@ -386,7 +396,7 @@ void AsyncWebSocketClient::_runQueue() {
continue;
}
if (space > (size_t)(ctrl.len() - 1)) {
async_ws_log_v("WS[%" PRIu32 "] Sending control frame: %" PRIu8 ", len: %" PRIu8, _clientId, ctrl.opcode(), ctrl.len());
async_ws_log_v("[%s][%" PRIu32 "] SEND CTRL %" PRIu8, _server->url(), _clientId, ctrl.opcode());
ctrl.send(_client);
space = webSocketSendFrameWindow(_client);
}
@@ -398,9 +408,10 @@ void AsyncWebSocketClient::_runQueue() {
for (auto &msg : _messageQueue) {
if (msg._remainingBytesToSend()) {
async_ws_log_v(
"WS[%" PRIu32 "] Send message fragment: %u/%u, acked: %u/%u", _clientId, msg._remainingBytesToSend(), msg._sent + msg._remainingBytesToSend(),
msg._acked, msg._ack
"[%s][%" PRIu32 "][%" PRIu8 "] SEND %u/%u (acked: %u/%u)", _server->url(), _clientId, msg._opcode, msg._sent, msg._WSbuffer->size(), msg._acked,
msg._ack
);
// will use all the remaining space, or all the remaining bytes to send, whichever is smaller
msg.send(_client);
space = webSocketSendFrameWindow(_client);
@@ -408,12 +419,12 @@ void AsyncWebSocketClient::_runQueue() {
// If we haven't finished sending this message, we must stop here to preserve WebSocket ordering.
// We can only pipeline subsequent messages if the current one is fully passed to TCP buffer.
if (msg._remainingBytesToSend()) {
async_ws_log_v("[%s][%" PRIu32 "][%" PRIu8 "] NO_SPACE", _server->url(), _clientId, msg._opcode);
break;
}
}
} else if (!space) {
// not enough space for another message
if (!space) {
async_ws_log_v("[%s][%" PRIu32 "] NO_SPACE", _server->url(), _clientId);
break;
}
}
@@ -452,6 +463,7 @@ bool AsyncWebSocketClient::_queueControl(uint8_t opcode, const uint8_t *data, si
#endif
_controlQueue.emplace_back(opcode, data, len, mask);
async_ws_log_v("[%s][%" PRIu32 "] QUEUE CTRL (%u) << %" PRIu8, _server->url(), _clientId, _controlQueue.size(), opcode);
if (_client && _client->canSend()) {
_runQueue();
@@ -485,16 +497,17 @@ bool AsyncWebSocketClient::_queueMessage(AsyncWebSocketSharedBuffer buffer, uint
_client->close();
}
async_ws_log_e("Too many messages queued: closing connection");
async_ws_log_w("[%s][%" PRIu32 "] Too many messages queued: closing connection", _server->url(), _clientId);
} else {
async_ws_log_e("Too many messages queued: discarding new message");
async_ws_log_w("[%s][%" PRIu32 "] Too many messages queued: discarding new message", _server->url(), _clientId);
}
return false;
}
_messageQueue.emplace_back(buffer, opcode, mask);
async_ws_log_v("[%s][%" PRIu32 "] QUEUE MSG (%u/%u) << %" PRIu8, _server->url(), _clientId, _messageQueue.size(), WS_MAX_QUEUED_MESSAGES, opcode);
if (_client && _client->canSend()) {
_runQueue();
@@ -508,6 +521,8 @@ void AsyncWebSocketClient::close(uint16_t code, const char *message) {
return;
}
async_ws_log_w("[%s][%" PRIu32 "] CLOSE", _server->url(), _clientId);
_status = WS_DISCONNECTING;
if (code) {
@@ -541,21 +556,20 @@ bool AsyncWebSocketClient::ping(const uint8_t *data, size_t len) {
return _status == WS_CONNECTED && _queueControl(WS_PING, data, len);
}
void AsyncWebSocketClient::_onError(int8_t) {
// Serial.println("onErr");
void AsyncWebSocketClient::_onError(int8_t err) {
async_ws_log_v("[%s][%" PRIu32 "] ERROR %" PRIi8, _server->url(), _clientId, static_cast<int8_t>(err));
}
void AsyncWebSocketClient::_onTimeout(uint32_t time) {
if (!_client) {
return;
}
// Serial.println("onTime");
(void)time;
async_ws_log_v("[%s][%" PRIu32 "] TIMEOUT %" PRIu32, _server->url(), _clientId, time);
_client->close();
}
void AsyncWebSocketClient::_onDisconnect() {
// Serial.println("onDis");
async_ws_log_v("[%s][%" PRIu32 "] DISCONNECT", _server->url(), _clientId);
_client = nullptr;
_server->_handleDisconnect(this);
}
@@ -566,7 +580,7 @@ void AsyncWebSocketClient::_onData(void *pbuf, size_t plen) {
while (plen > 0) {
async_ws_log_v(
"WS[%" PRIu32 "] _onData: plen: %" PRIu32 ", _pstate: %" PRIu8 ", _status: %" PRIu8, _clientId, plen, _pstate, static_cast<uint8_t>(_status)
"[%s][%" PRIu32 "] DATA plen: %" PRIu32 ", _pstate: %" PRIu8 ", _status: %" PRIu8, _server->url(), _clientId, plen, _pstate, static_cast<uint8_t>(_status)
);
if (_pstate == STATE_FRAME_START) {
@@ -595,8 +609,8 @@ void AsyncWebSocketClient::_onData(void *pbuf, size_t plen) {
}
async_ws_log_v(
"WS[%" PRIu32 "] _pinfo: index: %" PRIu64 ", final: %" PRIu8 ", opcode: %" PRIu8 ", masked: %" PRIu8 ", len: %" PRIu64, _clientId, _pinfo.index,
_pinfo.final, _pinfo.opcode, _pinfo.masked, _pinfo.len
"[%s][%" PRIu32 "] DATA _pinfo: index: %" PRIu64 ", final: %" PRIu8 ", opcode: %" PRIu8 ", masked: %" PRIu8 ", len: %" PRIu64, _server->url(), _clientId,
_pinfo.index, _pinfo.final, _pinfo.opcode, _pinfo.masked, _pinfo.len
);
// Handle fragmented mask data - Safari may split the 4-byte mask across multiple packets
@@ -608,7 +622,7 @@ void AsyncWebSocketClient::_onData(void *pbuf, size_t plen) {
if (plen == 0) {
// Safari close frame edge case: masked bit set but no mask data
if (_pinfo.opcode == WS_DISCONNECT) {
async_ws_log_v("WS[%" PRIu32 "] close frame with incomplete mask, treating as unmasked", _clientId);
async_ws_log_v("[%s][%" PRIu32 "] DATA close frame with incomplete mask, treating as unmasked", _server->url(), _clientId);
_pinfo.masked = 0;
_pinfo.index = 0;
_pinfo.len = 0;
@@ -618,7 +632,7 @@ void AsyncWebSocketClient::_onData(void *pbuf, size_t plen) {
// wait for more data
_pstate = STATE_FRAME_MASK;
async_ws_log_v("WS[%" PRIu32 "] waiting for more mask data: read: %" PRIu8 "/4", _clientId, _pinfo.masked - 1);
async_ws_log_v("[%s][%" PRIu32 "] DATA waiting for more mask data: read: %" PRIu8 "/4", _server->url(), _clientId, _pinfo.masked - 1);
return;
}
@@ -634,7 +648,7 @@ void AsyncWebSocketClient::_onData(void *pbuf, size_t plen) {
// restore masked to 1 for backward compatibility
if (_pinfo.masked >= 5) {
async_ws_log_v("WS[%" PRIu32 "] mask read complete", _clientId);
async_ws_log_v("[%s][%" PRIu32 "] DATA mask read complete", _server->url(), _clientId);
_pinfo.masked = 1;
}
@@ -663,7 +677,7 @@ void AsyncWebSocketClient::_onData(void *pbuf, size_t plen) {
if (datalen > 0) {
async_ws_log_v(
"WS[%" PRIu32 "] processing next fragment of %s frame %" PRIu32 ", index: %" PRIu64 ", len: %" PRIu32 "", _clientId,
"[%s][%" PRIu32 "] DATA processing next fragment of %s frame %" PRIu32 ", index: %" PRIu64 ", len: %" PRIu32 "", _server->url(), _clientId,
(_pinfo.message_opcode == WS_TEXT) ? "text" : "binary", _pinfo.num, _pinfo.index, (uint32_t)datalen
);
_handleDataEvent(data, datalen, datalen == plen); // datalen == plen means that we are processing the last part of the current TCP packet
@@ -676,7 +690,7 @@ void AsyncWebSocketClient::_onData(void *pbuf, size_t plen) {
_pstate = STATE_FRAME_START;
if (_pinfo.opcode == WS_DISCONNECT) {
async_ws_log_v("WS[%" PRIu32 "] processing disconnect", _clientId);
async_ws_log_v("[%s][%" PRIu32 "] DATA WS_DISCONNECT", _server->url(), _clientId);
if (datalen) {
uint16_t reasonCode = (uint16_t)(data[0] << 8) + data[1];
@@ -699,19 +713,19 @@ void AsyncWebSocketClient::_onData(void *pbuf, size_t plen) {
}
} else if (_pinfo.opcode == WS_PING) {
async_ws_log_v("WS[%" PRIu32 "] processing ping", _clientId);
async_ws_log_v("[%s][%" PRIu32 "] DATA PING", _server->url(), _clientId);
_server->_handleEvent(this, WS_EVT_PING, NULL, NULL, 0);
_queueControl(WS_PONG, data, datalen);
} else if (_pinfo.opcode == WS_PONG) {
async_ws_log_v("WS[%" PRIu32 "] processing pong", _clientId);
async_ws_log_v("[%s][%" PRIu32 "] DATA PONG", _server->url(), _clientId);
if (datalen != AWSC_PING_PAYLOAD_LEN || memcmp(AWSC_PING_PAYLOAD, data, AWSC_PING_PAYLOAD_LEN) != 0) {
_server->_handleEvent(this, WS_EVT_PONG, NULL, NULL, 0);
}
} else if (_pinfo.opcode < WS_DISCONNECT) { // continuation or text/binary frame
async_ws_log_v(
"WS[%" PRIu32 "] processing final fragment of %s frame %" PRIu32 ", index: %" PRIu64 ", len: %" PRIu32 "", _clientId,
"[%s][%" PRIu32 "] DATA processing final fragment of %s frame %" PRIu32 ", index: %" PRIu64 ", len: %" PRIu32 "", _server->url(), _clientId,
(_pinfo.message_opcode == WS_TEXT) ? "text" : "binary", _pinfo.num, _pinfo.index, (uint32_t)datalen
);
@@ -728,7 +742,9 @@ void AsyncWebSocketClient::_onData(void *pbuf, size_t plen) {
// unexpected frame error, close connection
_pstate = STATE_FRAME_START;
async_ws_log_v("frame error: len: %u, index: %llu, total: %llu\n", datalen, _pinfo.index, _pinfo.len);
async_ws_log_v(
"[%s][%" PRIu32 "] DATA frame error: len: %u, index: %" PRIu64 ", total: %" PRIu64 "\n", _server->url(), _clientId, datalen, _pinfo.index, _pinfo.len
);
_status = WS_DISCONNECTING;
if (_client) {
@@ -972,6 +988,9 @@ void AsyncWebSocket::_handleEvent(AsyncWebSocketClient *client, AwsEventType typ
}
AsyncWebSocketClient *AsyncWebSocket::_newClient(AsyncWebServerRequest *request) {
#ifdef ESP32
std::lock_guard<std::recursive_mutex> lock(_lock);
#endif
_clients.emplace_back(request, this);
// we've just detached AsyncTCP client from AsyncWebServerRequest
_handleEvent(&_clients.back(), WS_EVT_CONNECT, request, NULL, 0);
@@ -981,6 +1000,9 @@ AsyncWebSocketClient *AsyncWebSocket::_newClient(AsyncWebServerRequest *request)
}
void AsyncWebSocket::_handleDisconnect(AsyncWebSocketClient *client) {
#ifdef ESP32
std::lock_guard<std::recursive_mutex> lock(_lock);
#endif
const auto client_id = client->id();
const auto iter = std::find_if(std::begin(_clients), std::end(_clients), [client_id](const AsyncWebSocketClient &c) {
return c.id() == client_id;
@@ -991,12 +1013,18 @@ void AsyncWebSocket::_handleDisconnect(AsyncWebSocketClient *client) {
}
bool AsyncWebSocket::availableForWriteAll() {
#ifdef ESP32
std::lock_guard<std::recursive_mutex> lock(_lock);
#endif
return std::none_of(std::begin(_clients), std::end(_clients), [](const AsyncWebSocketClient &c) {
return c.queueIsFull();
});
}
bool AsyncWebSocket::availableForWrite(uint32_t id) {
#ifdef ESP32
std::lock_guard<std::recursive_mutex> lock(_lock);
#endif
const auto iter = std::find_if(std::begin(_clients), std::end(_clients), [id](const AsyncWebSocketClient &c) {
return c.id() == id;
});
@@ -1007,12 +1035,18 @@ bool AsyncWebSocket::availableForWrite(uint32_t id) {
}
size_t AsyncWebSocket::count() const {
#ifdef ESP32
std::lock_guard<std::recursive_mutex> lock(_lock);
#endif
return std::count_if(std::begin(_clients), std::end(_clients), [](const AsyncWebSocketClient &c) {
return c.status() == WS_CONNECTED;
});
}
AsyncWebSocketClient *AsyncWebSocket::client(uint32_t id) {
#ifdef ESP32
std::lock_guard<std::recursive_mutex> lock(_lock);
#endif
const auto iter = std::find_if(_clients.begin(), _clients.end(), [id](const AsyncWebSocketClient &c) {
return c.id() == id && c.status() == WS_CONNECTED;
});
@@ -1030,6 +1064,9 @@ void AsyncWebSocket::close(uint32_t id, uint16_t code, const char *message) {
}
void AsyncWebSocket::closeAll(uint16_t code, const char *message) {
#ifdef ESP32
std::lock_guard<std::recursive_mutex> lock(_lock);
#endif
for (auto &c : _clients) {
if (c.status() == WS_CONNECTED) {
c.close(code, message);
@@ -1038,7 +1075,12 @@ void AsyncWebSocket::closeAll(uint16_t code, const char *message) {
}
void AsyncWebSocket::cleanupClients(uint16_t maxClients) {
if (count() > maxClients) {
#ifdef ESP32
std::lock_guard<std::recursive_mutex> lock(_lock);
#endif
const size_t c = count();
if (c > maxClients) {
async_ws_log_v("[%s] CLEANUP %" PRIu32 " (%u/%" PRIu16 ")", _url.c_str(), _clients.front().id(), c, maxClients);
_clients.front().close();
}
@@ -1056,6 +1098,9 @@ bool AsyncWebSocket::ping(uint32_t id, const uint8_t *data, size_t len) {
}
AsyncWebSocket::SendStatus AsyncWebSocket::pingAll(const uint8_t *data, size_t len) {
#ifdef ESP32
std::lock_guard<std::recursive_mutex> lock(_lock);
#endif
size_t hit = 0;
size_t miss = 0;
for (auto &c : _clients) {
@@ -1164,6 +1209,9 @@ AsyncWebSocket::SendStatus AsyncWebSocket::textAll(AsyncWebSocketMessageBuffer *
}
AsyncWebSocket::SendStatus AsyncWebSocket::textAll(AsyncWebSocketSharedBuffer buffer) {
#ifdef ESP32
std::lock_guard<std::recursive_mutex> lock(_lock);
#endif
size_t hit = 0;
size_t miss = 0;
for (auto &c : _clients) {
@@ -1253,6 +1301,9 @@ AsyncWebSocket::SendStatus AsyncWebSocket::binaryAll(AsyncWebSocketMessageBuffer
return status;
}
AsyncWebSocket::SendStatus AsyncWebSocket::binaryAll(AsyncWebSocketSharedBuffer buffer) {
#ifdef ESP32
std::lock_guard<std::recursive_mutex> lock(_lock);
#endif
size_t hit = 0;
size_t miss = 0;
for (auto &c : _clients) {
+1 -1
View File
@@ -373,7 +373,7 @@ private:
AwsHandshakeHandler _handshakeHandler;
bool _enabled;
#ifdef ESP32
mutable std::mutex _lock;
mutable std::recursive_mutex _lock;
#endif
public:
+177 -31
View File
@@ -41,8 +41,6 @@
#include <ESPAsyncTCP.h>
#elif defined(TARGET_RP2040) || defined(TARGET_RP2350) || defined(PICO_RP2040) || defined(PICO_RP2350)
#include <RPAsyncTCP.h>
#include <HTTP_Method.h>
#include <http_parser.h>
#else
#error Platform not supported
#endif
@@ -68,6 +66,12 @@
#define ASYNCWEBSERVER_WIFI_SUPPORTED 0
#endif
// Enable integration with other HTTP libraries
#if defined(HTTP_ANY) || defined(http_parser_h)
#define ASYNCWEBSERVER_HTTP_METHOD_INTEGRATION
#define ASYNCWEBSERVER_NO_GLOBAL_HTTP_METHODS
#endif
class AsyncWebServer;
class AsyncWebServerRequest;
class AsyncWebServerResponse;
@@ -80,29 +84,170 @@ class AsyncCallbackWebHandler;
class AsyncResponseStream;
class AsyncMiddlewareChain;
#if defined(TARGET_RP2040) || defined(TARGET_RP2350) || defined(PICO_RP2040) || defined(PICO_RP2350)
typedef enum http_method WebRequestMethod;
#else
#ifndef WEBSERVER_H
typedef enum {
HTTP_GET = 0b0000000000000001,
HTTP_POST = 0b0000000000000010,
HTTP_DELETE = 0b0000000000000100,
HTTP_PUT = 0b0000000000001000,
HTTP_PATCH = 0b0000000000010000,
HTTP_HEAD = 0b0000000000100000,
HTTP_OPTIONS = 0b0000000001000000,
HTTP_PROPFIND = 0b0000000010000000,
HTTP_LOCK = 0b0000000100000000,
HTTP_UNLOCK = 0b0000001000000000,
HTTP_PROPPATCH = 0b0000010000000000,
HTTP_MKCOL = 0b0000100000000000,
HTTP_MOVE = 0b0001000000000000,
HTTP_COPY = 0b0010000000000000,
HTTP_RESERVED = 0b0100000000000000,
HTTP_ANY = 0b0111111111111111,
} WebRequestMethod;
// Namespace for web request method defines
namespace AsyncWebRequestMethod {
// The long name here is because we sometimes include this in the global namespace
enum AsyncWebRequestMethodType : uint32_t {
HTTP_UNKNOWN = 0u,
HTTP_DELETE = 1u << 0,
HTTP_GET = 1u << 1,
HTTP_HEAD = 1u << 2,
HTTP_POST = 1u << 3,
HTTP_PUT = 1u << 4,
/* pathological */
HTTP_CONNECT = 1u << 5,
HTTP_OPTIONS = 1u << 6,
HTTP_TRACE = 1u << 7,
/* WebDAV */
HTTP_COPY = 1u << 8,
HTTP_LOCK = 1u << 9,
HTTP_MKCOL = 1u << 10,
HTTP_MOVE = 1u << 11,
HTTP_PROPFIND = 1u << 12,
HTTP_PROPPATCH = 1u << 13,
HTTP_SEARCH = 1u << 14,
HTTP_UNLOCK = 1u << 15,
HTTP_BIND = 1u << 16,
HTTP_REBIND = 1u << 17,
HTTP_UNBIND = 1u << 18,
HTTP_ACL = 1u << 19,
/* subversion */
// HTTP_REPORT
// HTTP_MKACTIVITY
// HTTP_CHECKOUT
// HTTP_MERGE
/* upnp */
// HTTP_MSEARCH
// HTTP_NOTIFY
// HTTP_SUBSCRIBE
// HTTP_UNSUBSCRIBE
/* RFC-5789 */
HTTP_PATCH = 1u << 20,
HTTP_PURGE = 1u << 21,
/* CalDAV */
// HTTP_MKCALENDAR
/* RFC-2068, section 19.6.1.2 */
HTTP_LINK = 1u << 22,
HTTP_UNLINK = 1u << 23,
/* icecast */
// HTTP_SOURCE
HTTP_INVALID = 1u << 31 // Sentinel
};
}; // namespace AsyncWebRequestMethod
typedef AsyncWebRequestMethod::AsyncWebRequestMethodType WebRequestMethod;
class WebRequestMethodComposite {
uint32_t mask;
private:
constexpr WebRequestMethodComposite(uint32_t m) : mask(m){};
public:
// Default constructor: by default, matches nothing
constexpr WebRequestMethodComposite() : mask(0){};
// Constructor: allows implicit conversion from WebRequestMethod
constexpr WebRequestMethodComposite(WebRequestMethod m) : mask(static_cast<uint32_t>(m)){};
// Combine composites
constexpr inline WebRequestMethodComposite operator|(const WebRequestMethodComposite &r) const {
return WebRequestMethodComposite(mask | r.mask);
};
// == operator for composite
constexpr inline bool operator==(const WebRequestMethodComposite &r) const {
return mask == r.mask;
};
constexpr inline bool operator!=(const WebRequestMethodComposite &r) const {
return mask != r.mask;
};
// Check for a match
constexpr inline bool matches(WebRequestMethod m) const {
return mask & static_cast<uint32_t>(m);
};
constexpr inline bool operator&(WebRequestMethod m) const {
return matches(m);
}
// Super cool feature: integration with platform `http_method` enum
#ifdef ASYNCWEBSERVER_HTTP_METHOD_INTEGRATION
// Conversion function for integration with external libraries.
// Horrible ternary implementation for C++11 compatibility.
#define MAP_EXTERNAL_TERNARY(x) (t == http_method::x) ? static_cast<uint32_t>(WebRequestMethod::x)
constexpr static inline uint32_t map_http_method(http_method t) {
return MAP_EXTERNAL_TERNARY(HTTP_DELETE)
: MAP_EXTERNAL_TERNARY(HTTP_GET)
: MAP_EXTERNAL_TERNARY(HTTP_HEAD)
: MAP_EXTERNAL_TERNARY(HTTP_POST)
: MAP_EXTERNAL_TERNARY(HTTP_PUT)
: MAP_EXTERNAL_TERNARY(HTTP_CONNECT)
: MAP_EXTERNAL_TERNARY(HTTP_OPTIONS)
: MAP_EXTERNAL_TERNARY(HTTP_TRACE)
: MAP_EXTERNAL_TERNARY(HTTP_COPY)
: MAP_EXTERNAL_TERNARY(HTTP_LOCK)
: MAP_EXTERNAL_TERNARY(HTTP_MKCOL)
: MAP_EXTERNAL_TERNARY(HTTP_MOVE)
: MAP_EXTERNAL_TERNARY(HTTP_PROPFIND)
: MAP_EXTERNAL_TERNARY(HTTP_PROPPATCH)
: MAP_EXTERNAL_TERNARY(HTTP_SEARCH)
: MAP_EXTERNAL_TERNARY(HTTP_UNLOCK)
: MAP_EXTERNAL_TERNARY(HTTP_BIND)
: MAP_EXTERNAL_TERNARY(HTTP_REBIND)
: MAP_EXTERNAL_TERNARY(HTTP_UNBIND)
: MAP_EXTERNAL_TERNARY(HTTP_ACL)
: MAP_EXTERNAL_TERNARY(HTTP_PATCH)
: MAP_EXTERNAL_TERNARY(HTTP_PURGE)
: MAP_EXTERNAL_TERNARY(HTTP_LINK)
: MAP_EXTERNAL_TERNARY(HTTP_UNLINK)
#if defined(HTTP_ANY)
: (t == HTTP_ANY) ? static_cast<uint32_t>(WebRequestMethod::HTTP_INVALID) - 1
#endif
: static_cast<uint32_t>(WebRequestMethod::HTTP_INVALID);
}
#undef MAP_EXTERNAL_TERNARY
constexpr WebRequestMethodComposite(http_method m) : mask(map_http_method(m)){};
#endif
}; // WebRequestMethodComposite
// Operator| for WebRequestMethod: combine to a WebRequestMethodComposite
constexpr inline WebRequestMethodComposite operator|(WebRequestMethod l, WebRequestMethod r) {
return static_cast<WebRequestMethodComposite>(l) | r;
};
namespace AsyncWebRequestMethod {
constexpr WebRequestMethodComposite HTTP_ALL = static_cast<WebRequestMethod>(static_cast<uint32_t>(HTTP_INVALID) - 1);
// Support HTTP_ANY if we can
#ifndef HTTP_ANY
constexpr WebRequestMethodComposite HTTP_ANY = HTTP_ALL;
#endif
} // namespace AsyncWebRequestMethod
// WebRequestMethod string conversion functions
namespace asyncsrv {
WebRequestMethod stringToMethod(const String &);
const char *methodToString(WebRequestMethod);
} // namespace asyncsrv
#if !defined(ASYNCWEBSERVER_NO_GLOBAL_HTTP_METHODS)
// Import the method enum values to the global namespace
using namespace AsyncWebRequestMethod;
#endif
#ifndef HAVE_FS_FILE_OPEN_MODE
@@ -122,7 +267,6 @@ public:
#define RESPONSE_TRY_AGAIN 0xFFFFFFFF
#define RESPONSE_STREAM_BUFFER_SIZE 1460
typedef uint16_t WebRequestMethodComposite;
typedef std::function<void(void)> ArDisconnectHandler;
/*
@@ -254,7 +398,7 @@ private:
uint8_t _parseState;
uint8_t _version;
WebRequestMethodComposite _method;
WebRequestMethod _method;
String _url;
String _host;
String _contentType;
@@ -344,7 +488,7 @@ public:
uint8_t version() const {
return _version;
}
WebRequestMethodComposite method() const {
WebRequestMethod method() const {
return _method;
}
const String &url() const {
@@ -363,7 +507,9 @@ public:
return _isMultipart;
}
const char *methodToString() const;
inline const char *methodToString() const {
return asyncsrv::methodToString(_method);
};
const char *requestedConnTypeToString() const;
RequestedConnectionType requestedConnType() const {
@@ -372,10 +518,10 @@ public:
bool isExpectedRequestedConnType(RequestedConnectionType erct1, RequestedConnectionType erct2 = RCT_NOT_USED, RequestedConnectionType erct3 = RCT_NOT_USED)
const;
bool isWebSocketUpgrade() const {
return _method == HTTP_GET && isExpectedRequestedConnType(RCT_WS);
return _method == AsyncWebRequestMethod::HTTP_GET && isExpectedRequestedConnType(RCT_WS);
}
bool isSSE() const {
return _method == HTTP_GET && isExpectedRequestedConnType(RCT_EVENT);
return _method == AsyncWebRequestMethod::HTTP_GET && isExpectedRequestedConnType(RCT_EVENT);
}
bool isHTTP() const {
return isExpectedRequestedConnType(RCT_DEFAULT, RCT_HTTP);
@@ -1545,7 +1691,7 @@ public:
bool removeHandler(AsyncWebHandler *handler);
AsyncCallbackWebHandler &on(AsyncURIMatcher uri, ArRequestHandlerFunction onRequest) {
return on(std::move(uri), HTTP_ANY, onRequest);
return on(std::move(uri), AsyncWebRequestMethod::HTTP_ALL, onRequest);
}
AsyncCallbackWebHandler &on(
AsyncURIMatcher uri, WebRequestMethodComposite method, ArRequestHandlerFunction onRequest, ArUploadHandlerFunction onUpload = nullptr,
+1 -1
View File
@@ -249,7 +249,7 @@ void AsyncCorsMiddleware::run(AsyncWebServerRequest *request, ArMiddlewareNext n
// Origin header ? => CORS handling
if (request->hasHeader(asyncsrv::T_CORS_O)) {
// check if this is a preflight request => handle it and return
if (request->method() == HTTP_OPTIONS) {
if (request->method() == AsyncWebRequestMethod::HTTP_OPTIONS) {
AsyncWebServerResponse *response = request->beginResponse(200);
addCORSHeaders(request, response);
request->send(response);
+3 -2
View File
@@ -7,6 +7,7 @@
#include <time.h>
#include <string>
#include <utility>
class AsyncStaticWebHandler : public AsyncWebHandler {
using File = fs::File;
@@ -62,10 +63,10 @@ protected:
bool _isRegex;
public:
AsyncCallbackWebHandler() : _uri(), _method(HTTP_ANY), _onRequest(NULL), _onUpload(NULL), _onBody(NULL), _isRegex(false) {}
AsyncCallbackWebHandler() : _uri(), _method(AsyncWebRequestMethod::HTTP_ALL), _onRequest(NULL), _onUpload(NULL), _onBody(NULL), _isRegex(false) {}
void setUri(AsyncURIMatcher uri);
void setMethod(WebRequestMethodComposite method) {
_method = method;
_method = std::move(method);
}
void onRequest(ArRequestHandlerFunction fn) {
_onRequest = fn;
+3 -3
View File
@@ -103,7 +103,7 @@ AsyncStaticWebHandler &AsyncStaticWebHandler::setLastModified() {
}
bool AsyncStaticWebHandler::canHandle(AsyncWebServerRequest *request) const {
return request->isHTTP() && request->method() == HTTP_GET && request->url().startsWith(_uri) && _getFile(request);
return request->isHTTP() && request->method() == AsyncWebRequestMethod::HTTP_GET && request->url().startsWith(_uri) && _getFile(request);
}
bool AsyncStaticWebHandler::_getFile(AsyncWebServerRequest *request) const {
@@ -218,7 +218,7 @@ void AsyncStaticWebHandler::handleRequest(AsyncWebServerRequest *request) {
//File is a gz, get etag from CRC in trailer
if (!AsyncWebServerRequest::_getEtag(request->_tempFile, etag)) {
// File is corrupted or invalid
async_ws_log_e("File is corrupted or invalid: %s", tempFileName);
async_ws_log_w("File is corrupted or invalid: %s", tempFileName);
request->send(404);
return;
}
@@ -300,7 +300,7 @@ void AsyncCallbackWebHandler::setUri(AsyncURIMatcher uri) {
}
bool AsyncCallbackWebHandler::canHandle(AsyncWebServerRequest *request) const {
if (!_onRequest || !request->isHTTP() || !(_method & request->method())) {
if (!_onRequest || !request->isHTTP() || !_method.matches(request->method())) {
return false;
}
return _uri.matches(request);
+100 -83
View File
@@ -39,11 +39,12 @@ enum {
};
AsyncWebServerRequest::AsyncWebServerRequest(AsyncWebServer *s, AsyncClient *c)
: _client(c), _server(s), _handler(NULL), _response(NULL), _onDisconnectfn(NULL), _temp(), _parseState(PARSE_REQ_START), _version(0), _method(HTTP_ANY),
_url(), _host(), _contentType(), _boundary(), _authorization(), _reqconntype(RCT_HTTP), _authMethod(AsyncAuthType::AUTH_NONE), _isMultipart(false),
_isPlainPost(false), _expectingContinue(false), _contentLength(0), _parsedLength(0), _multiParseState(0), _boundaryPosition(0), _itemStartIndex(0),
_itemSize(0), _itemName(), _itemFilename(), _itemType(), _itemValue(), _itemBuffer(0), _itemBufferIndex(0), _itemIsFile(false), _chunkStartIndex(0),
_chunkOffset(0), _chunkSize(0), _chunkedParseState(CHUNK_NONE), _chunkedLastChar(0), _tempObject(NULL) {
: _client(c), _server(s), _handler(NULL), _response(NULL), _onDisconnectfn(NULL), _temp(), _parseState(PARSE_REQ_START), _version(0),
_method(AsyncWebRequestMethod::HTTP_UNKNOWN), _url(), _host(), _contentType(), _boundary(), _authorization(), _reqconntype(RCT_HTTP),
_authMethod(AsyncAuthType::AUTH_NONE), _isMultipart(false), _isPlainPost(false), _expectingContinue(false), _contentLength(0), _parsedLength(0),
_multiParseState(0), _boundaryPosition(0), _itemStartIndex(0), _itemSize(0), _itemName(), _itemFilename(), _itemType(), _itemValue(), _itemBuffer(0),
_itemBufferIndex(0), _itemIsFile(false), _chunkStartIndex(0), _chunkOffset(0), _chunkSize(0), _chunkedParseState(CHUNK_NONE), _chunkedLastChar(0),
_tempObject(NULL) {
c->onError(
[](void *r, AsyncClient *c, int8_t error) {
(void)c;
@@ -313,35 +314,8 @@ bool AsyncWebServerRequest::_parseReqHead() {
String u = _temp.substring(m.length() + 1, index);
_temp = _temp.substring(index + 1);
if (m == T_GET) {
_method = HTTP_GET;
} else if (m == T_POST) {
_method = HTTP_POST;
} else if (m == T_DELETE) {
_method = HTTP_DELETE;
} else if (m == T_PUT) {
_method = HTTP_PUT;
} else if (m == T_PATCH) {
_method = HTTP_PATCH;
} else if (m == T_HEAD) {
_method = HTTP_HEAD;
} else if (m == T_OPTIONS) {
_method = HTTP_OPTIONS;
} else if (m == T_PROPFIND) {
_method = HTTP_PROPFIND;
} else if (m == T_LOCK) {
_method = HTTP_LOCK;
} else if (m == T_UNLOCK) {
_method = HTTP_UNLOCK;
} else if (m == T_PROPPATCH) {
_method = HTTP_PROPPATCH;
} else if (m == T_MKCOL) {
_method = HTTP_MKCOL;
} else if (m == T_MOVE) {
_method = HTTP_MOVE;
} else if (m == T_COPY) {
_method = HTTP_COPY;
} else {
_method = asyncsrv::stringToMethod(m);
if (_method == AsyncWebRequestMethod::HTTP_INVALID) {
return false;
}
@@ -1310,55 +1284,6 @@ String AsyncWebServerRequest::urlDecode(const String &text) const {
return decoded;
}
const char *AsyncWebServerRequest::methodToString() const {
if (_method == HTTP_ANY) {
return T_ANY;
}
if (_method & HTTP_GET) {
return T_GET;
}
if (_method & HTTP_POST) {
return T_POST;
}
if (_method & HTTP_DELETE) {
return T_DELETE;
}
if (_method & HTTP_PUT) {
return T_PUT;
}
if (_method & HTTP_PATCH) {
return T_PATCH;
}
if (_method & HTTP_HEAD) {
return T_HEAD;
}
if (_method & HTTP_OPTIONS) {
return T_OPTIONS;
}
if (_method & HTTP_PROPFIND) {
return T_PROPFIND;
}
if (_method & HTTP_LOCK) {
return T_LOCK;
}
if (_method & HTTP_UNLOCK) {
return T_UNLOCK;
}
if (_method & HTTP_PROPPATCH) {
return T_PROPPATCH;
}
if (_method & HTTP_MKCOL) {
return T_MKCOL;
}
if (_method & HTTP_MOVE) {
return T_MOVE;
}
if (_method & HTTP_COPY) {
return T_COPY;
}
return T_UNKNOWN;
}
const char *AsyncWebServerRequest::requestedConnTypeToString() const {
switch (_reqconntype) {
case RCT_NOT_USED: return T_RCT_NOT_USED;
@@ -1380,3 +1305,95 @@ AsyncClient *AsyncWebServerRequest::clientRelease() {
_client = nullptr;
return c;
}
namespace asyncsrv {
// WebRequestMethod conversions
WebRequestMethod stringToMethod(const String &m) {
if (m == T_GET) {
return AsyncWebRequestMethod::HTTP_GET;
} else if (m == T_POST) {
return AsyncWebRequestMethod::HTTP_POST;
} else if (m == T_DELETE) {
return AsyncWebRequestMethod::HTTP_DELETE;
} else if (m == T_PUT) {
return AsyncWebRequestMethod::HTTP_PUT;
} else if (m == T_PATCH) {
return AsyncWebRequestMethod::HTTP_PATCH;
} else if (m == T_HEAD) {
return AsyncWebRequestMethod::HTTP_HEAD;
} else if (m == T_OPTIONS) {
return AsyncWebRequestMethod::HTTP_OPTIONS;
} else if (m == T_TRACE) {
return AsyncWebRequestMethod::HTTP_TRACE;
} else if (m == T_CONNECT) {
return AsyncWebRequestMethod::HTTP_CONNECT;
} else if (m == T_PURGE) {
return AsyncWebRequestMethod::HTTP_PURGE;
} else if (m == T_LINK) {
return AsyncWebRequestMethod::HTTP_LINK;
} else if (m == T_UNLINK) {
return AsyncWebRequestMethod::HTTP_UNLINK;
} else if (m == T_PROPFIND) {
return AsyncWebRequestMethod::HTTP_PROPFIND;
} else if (m == T_LOCK) {
return AsyncWebRequestMethod::HTTP_LOCK;
} else if (m == T_UNLOCK) {
return AsyncWebRequestMethod::HTTP_UNLOCK;
} else if (m == T_PROPPATCH) {
return AsyncWebRequestMethod::HTTP_PROPPATCH;
} else if (m == T_MKCOL) {
return AsyncWebRequestMethod::HTTP_MKCOL;
} else if (m == T_MOVE) {
return AsyncWebRequestMethod::HTTP_MOVE;
} else if (m == T_COPY) {
return AsyncWebRequestMethod::HTTP_COPY;
} else if (m == T_SEARCH) {
return AsyncWebRequestMethod::HTTP_SEARCH;
} else if (m == T_BIND) {
return AsyncWebRequestMethod::HTTP_BIND;
} else if (m == T_REBIND) {
return AsyncWebRequestMethod::HTTP_REBIND;
} else if (m == T_UNBIND) {
return AsyncWebRequestMethod::HTTP_UNBIND;
} else if (m == T_ACL) {
return AsyncWebRequestMethod::HTTP_ACL;
} else {
return AsyncWebRequestMethod::HTTP_INVALID;
}
}
const char *methodToString(WebRequestMethod method) {
switch (method) {
case AsyncWebRequestMethod::HTTP_DELETE: return T_DELETE;
case AsyncWebRequestMethod::HTTP_GET: return T_GET;
case AsyncWebRequestMethod::HTTP_HEAD: return T_HEAD;
case AsyncWebRequestMethod::HTTP_POST: return T_POST;
case AsyncWebRequestMethod::HTTP_PUT: return T_PUT;
/* pathological */
case AsyncWebRequestMethod::HTTP_CONNECT: return T_CONNECT;
case AsyncWebRequestMethod::HTTP_OPTIONS: return T_OPTIONS;
case AsyncWebRequestMethod::HTTP_TRACE: return T_TRACE;
/* WebDAV */
case AsyncWebRequestMethod::HTTP_COPY: return T_COPY;
case AsyncWebRequestMethod::HTTP_LOCK: return T_LOCK;
case AsyncWebRequestMethod::HTTP_MKCOL: return T_MKCOL;
case AsyncWebRequestMethod::HTTP_MOVE: return T_MOVE;
case AsyncWebRequestMethod::HTTP_PROPFIND: return T_PROPFIND;
case AsyncWebRequestMethod::HTTP_PROPPATCH: return T_PROPPATCH;
case AsyncWebRequestMethod::HTTP_SEARCH: return T_SEARCH;
case AsyncWebRequestMethod::HTTP_UNLOCK: return T_UNLOCK;
case AsyncWebRequestMethod::HTTP_BIND: return T_BIND;
case AsyncWebRequestMethod::HTTP_REBIND: return T_REBIND;
case AsyncWebRequestMethod::HTTP_UNBIND: return T_UNBIND;
case AsyncWebRequestMethod::HTTP_ACL: return T_ACL;
/* RFC-5789 */
case AsyncWebRequestMethod::HTTP_PATCH: return T_PATCH;
case AsyncWebRequestMethod::HTTP_PURGE: return T_PURGE;
/* RFC-2068, section 19.6.1.2 */
case AsyncWebRequestMethod::HTTP_LINK: return T_LINK;
case AsyncWebRequestMethod::HTTP_UNLINK: return T_UNLINK;
// Unsupported
default: return T_UNKNOWN;
}
}
} // namespace asyncsrv
+2 -2
View File
@@ -158,7 +158,7 @@ AsyncCallbackWebHandler &AsyncWebServer::on(
) {
AsyncCallbackWebHandler *handler = new AsyncCallbackWebHandler();
handler->setUri(std::move(uri));
handler->setMethod(method);
handler->setMethod(std::move(method));
handler->onRequest(onRequest);
handler->onUpload(onUpload);
handler->onBody(onBody);
@@ -169,7 +169,7 @@ AsyncCallbackWebHandler &AsyncWebServer::on(
#if ASYNC_JSON_SUPPORT == 1
AsyncCallbackJsonWebHandler &AsyncWebServer::on(AsyncURIMatcher uri, WebRequestMethodComposite method, ArJsonRequestHandlerFunction onBody) {
AsyncCallbackJsonWebHandler *handler = new AsyncCallbackJsonWebHandler(std::move(uri), onBody);
handler->setMethod(method);
handler->setMethod(std::move(method));
addHandler(handler);
return *handler;
}
+10 -1
View File
@@ -104,7 +104,6 @@ static constexpr const char T_WWW_AUTH[] = "WWW-Authenticate";
static constexpr const char T_X_Expected_Entity_Length[] = "X-Expected-Entity-Length";
// HTTP Methods
static constexpr const char T_ANY[] = "ANY";
static constexpr const char T_GET[] = "GET";
static constexpr const char T_POST[] = "POST";
static constexpr const char T_PUT[] = "PUT";
@@ -120,6 +119,16 @@ static constexpr const char T_MKCOL[] = "MKCOL";
static constexpr const char T_MOVE[] = "MOVE";
static constexpr const char T_COPY[] = "COPY";
static constexpr const char T_UNKNOWN[] = "UNKNOWN";
static constexpr const char T_CONNECT[] = "CONNECT";
static constexpr const char T_TRACE[] = "TRACE";
static constexpr const char T_SEARCH[] = "SEARCH";
static constexpr const char T_BIND[] = "BIND";
static constexpr const char T_REBIND[] = "REBIND";
static constexpr const char T_UNBIND[] = "UNBIND";
static constexpr const char T_ACL[] = "ACL";
static constexpr const char T_PURGE[] = "PURGE";
static constexpr const char T_LINK[] = "LINK";
static constexpr const char T_UNLINK[] = "UNLINK";
// Req content types
static constexpr const char T_RCT_NOT_USED[] = "RCT_NOT_USED";