Update to 3.10.3
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -35,7 +35,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v5
|
||||
uses: actions/checkout@v6
|
||||
- name: Python
|
||||
uses: actions/setup-python@v6
|
||||
with:
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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: |
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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
@@ -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
@@ -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);
|
||||
}
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
@@ -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
@@ -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
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
+85
-34
@@ -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;
|
||||
@@ -616,9 +630,9 @@ void AsyncWebSocketClient::_onData(void *pbuf, size_t plen) {
|
||||
break;
|
||||
}
|
||||
|
||||
//wait for more data
|
||||
// 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) {
|
||||
|
||||
@@ -373,7 +373,7 @@ private:
|
||||
AwsHandshakeHandler _handshakeHandler;
|
||||
bool _enabled;
|
||||
#ifdef ESP32
|
||||
mutable std::mutex _lock;
|
||||
mutable std::recursive_mutex _lock;
|
||||
#endif
|
||||
|
||||
public:
|
||||
|
||||
+177
-31
@@ -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
@@ -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);
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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";
|
||||
|
||||
Reference in New Issue
Block a user