Aktualizace na verzi 3.3.23
This commit is contained in:
parent
2333497adc
commit
7c828c70d8
130
README.md
130
README.md
@ -15,8 +15,9 @@ Supports: WebSocket, SSE, Authentication, Arduino Json 7, File Upload, Static Fi
|
|||||||
|
|
||||||
This fork is based on [yubox-node-org/ESPAsyncWebServer](https://github.com/yubox-node-org/ESPAsyncWebServer) and includes all the concurrency fixes.
|
This fork is based on [yubox-node-org/ESPAsyncWebServer](https://github.com/yubox-node-org/ESPAsyncWebServer) and includes all the concurrency fixes.
|
||||||
|
|
||||||
- [Coordinate and dependencies](#coordinate-and-dependencies)
|
|
||||||
- [Changes in this fork](#changes-in-this-fork)
|
- [Changes in this fork](#changes-in-this-fork)
|
||||||
|
- [Dependencies](#dependencies)
|
||||||
|
- [Performance](#performance)
|
||||||
- [Important recommendations](#important-recommendations)
|
- [Important recommendations](#important-recommendations)
|
||||||
- [`AsyncWebSocketMessageBuffer` and `makeBuffer()`](#asyncwebsocketmessagebuffer-and-makebuffer)
|
- [`AsyncWebSocketMessageBuffer` and `makeBuffer()`](#asyncwebsocketmessagebuffer-and-makebuffer)
|
||||||
- [How to replace a response](#how-to-replace-a-response)
|
- [How to replace a response](#how-to-replace-a-response)
|
||||||
@ -25,20 +26,6 @@ This fork is based on [yubox-node-org/ESPAsyncWebServer](https://github.com/yubo
|
|||||||
- [Migration to Middleware to improve performance and memory usage](#migration-to-middleware-to-improve-performance-and-memory-usage)
|
- [Migration to Middleware to improve performance and memory usage](#migration-to-middleware-to-improve-performance-and-memory-usage)
|
||||||
- [Original Documentation](#original-documentation)
|
- [Original Documentation](#original-documentation)
|
||||||
|
|
||||||
## Coordinate and dependencies
|
|
||||||
|
|
||||||
**WARNING** The library name was changed from `ESP Async WebServer` to `ESPAsyncWebServer` as per the Arduino Lint recommendations.
|
|
||||||
|
|
||||||
```
|
|
||||||
mathieucarbou/ESPAsyncWebServer @ 3.3.7
|
|
||||||
```
|
|
||||||
|
|
||||||
Dependency:
|
|
||||||
|
|
||||||
- **ESP32**: `mathieucarbou/AsyncTCP @ 3.2.5` (Arduino IDE: [https://github.com/mathieucarbou/AsyncTCP#v3.2.5](https://github.com/mathieucarbou/AsyncTCP/releases))
|
|
||||||
- **ESP8266**: `esphome/ESPAsyncTCP-esphome @ 2.0.0` (Arduino IDE: [https://github.com/mathieucarbou/esphome-ESPAsyncTCP#v2.0.0](https://github.com/mathieucarbou/esphome-ESPAsyncTCP/releases/tag/v2.0.0))
|
|
||||||
- **RP2040**: `khoih-prog/AsyncTCP_RP2040W @ 1.2.0` (Arduino IDE: [https://github.com/khoih-prog/AsyncTCP_RP2040W#v1.2.0](https://github.com/khoih-prog/AsyncTCP_RP2040W/releases/tag/v1.2.0))
|
|
||||||
|
|
||||||
## Changes in this fork
|
## Changes in this fork
|
||||||
|
|
||||||
- (bug) A lot of bug fixes
|
- (bug) A lot of bug fixes
|
||||||
@ -55,6 +42,7 @@ Dependency:
|
|||||||
- (feat) **Resumable download** support using HEAD and bytes range
|
- (feat) **Resumable download** support using HEAD and bytes range
|
||||||
- (feat) `StreamConcat` example to show how to stream multiple files in one response
|
- (feat) `StreamConcat` example to show how to stream multiple files in one response
|
||||||
- (feat) Removed ESPIDF Editor (this is not the role of a web server library to do that - get the source files from the original repos if required)
|
- (feat) Removed ESPIDF Editor (this is not the role of a web server library to do that - get the source files from the original repos if required)
|
||||||
|
- (perf) [AsyncTCPSock](https://github.com/mathieucarbou/AsyncTCPSock) support: AsyncTCP can be ignored and AsyncTCPSock used instead
|
||||||
- (perf) `char*` overloads to avoid using `String`
|
- (perf) `char*` overloads to avoid using `String`
|
||||||
- (perf) `DEFAULT_MAX_WS_CLIENTS` to change the number of allows WebSocket clients and use `cleanupClients()` to help cleanup resources about dead clients
|
- (perf) `DEFAULT_MAX_WS_CLIENTS` to change the number of allows WebSocket clients and use `cleanupClients()` to help cleanup resources about dead clients
|
||||||
- (perf) `setCloseClientOnQueueFull(bool)` which can be set on a client to either close the connection or discard messages but not close the connection when the queue is full
|
- (perf) `setCloseClientOnQueueFull(bool)` which can be set on a client to either close the connection or discard messages but not close the connection when the queue is full
|
||||||
@ -64,6 +52,112 @@ Dependency:
|
|||||||
- (perf) Lot of code cleanup and optimizations
|
- (perf) Lot of code cleanup and optimizations
|
||||||
- (perf) Performance improvements in terms of memory, speed and size
|
- (perf) Performance improvements in terms of memory, speed and size
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## WARNING: Important notes about future version 4.x
|
||||||
|
|
||||||
|
This ESPAsyncWebServer fork is now at version 3.x.
|
||||||
|
|
||||||
|
Next version 4.x will:
|
||||||
|
|
||||||
|
1. Drop support for ESP8266, which goes EOL in a few years. All ESP8266 boards can be replaced by equivalent ESP32 boards.
|
||||||
|
2. Drop support for Arduino 2.x and ESP-IDF 4.x. The library will be compatible with Arduino 3.x and ESP-IDF 5.x.
|
||||||
|
3. Drop support for ArduinoJson 5.x and 6.x. The library will be compatible with ArduinoJson 7.x.
|
||||||
|
|
||||||
|
So if you need one of these feature, you will have to stick with 3.x or another fork.
|
||||||
|
|
||||||
|
## Dependencies
|
||||||
|
|
||||||
|
**WARNING** The library name was changed from `ESP Async WebServer` to `ESPAsyncWebServer` as per the Arduino Lint recommendations, but its name had to stay `ESP Async WebServer` in Arduino Registry.
|
||||||
|
|
||||||
|
**PlatformIO / pioarduino:**
|
||||||
|
|
||||||
|
```ini
|
||||||
|
lib_compat_mode = strict
|
||||||
|
lib_ldf_mode = chain
|
||||||
|
lib_deps = mathieucarbou/ESPAsyncWebServer @ 3.3.23
|
||||||
|
```
|
||||||
|
|
||||||
|
**Dependencies:**
|
||||||
|
|
||||||
|
- **ESP32 with AsyncTCP**: `mathieucarbou/AsyncTCP @ 3.2.14`
|
||||||
|
Arduino IDE: [https://github.com/mathieucarbou/AsyncTCP#v3.2.14](https://github.com/mathieucarbou/AsyncTCP/releases)
|
||||||
|
|
||||||
|
- **ESP32 with AsyncTCPSock**: `https://github.com/mathieucarbou/AsyncTCPSock/archive/refs/tags/v1.0.3-dev.zip`
|
||||||
|
|
||||||
|
- **ESP8266**: `esphome/ESPAsyncTCP-esphome @ 2.0.0`
|
||||||
|
Arduino IDE: [https://github.com/mathieucarbou/esphome-ESPAsyncTCP#v2.0.0](https://github.com/mathieucarbou/esphome-ESPAsyncTCP/releases/tag/v2.0.0)
|
||||||
|
|
||||||
|
- **RP2040**: `khoih-prog/AsyncTCP_RP2040W @ 1.2.0`
|
||||||
|
Arduino IDE: [https://github.com/khoih-prog/AsyncTCP_RP2040W#v1.2.0](https://github.com/khoih-prog/AsyncTCP_RP2040W/releases/tag/v1.2.0)
|
||||||
|
|
||||||
|
**AsyncTCPSock**
|
||||||
|
|
||||||
|
AsyncTCPSock can be used instead of AsyncTCP by excluding AsyncTCP from the library dependencies and adding AsyncTCPSock instead:
|
||||||
|
|
||||||
|
```ini
|
||||||
|
lib_compat_mode = strict
|
||||||
|
lib_ldf_mode = chain
|
||||||
|
lib_deps =
|
||||||
|
; mathieucarbou/AsyncTCP @ 3.2.14
|
||||||
|
https://github.com/mathieucarbou/AsyncTCPSock/archive/refs/tags/v1.0.3-dev.zip
|
||||||
|
mathieucarbou/ESPAsyncWebServer @ 3.3.23
|
||||||
|
lib_ignore =
|
||||||
|
AsyncTCP
|
||||||
|
mathieucarbou/AsyncTCP
|
||||||
|
```
|
||||||
|
|
||||||
|
## Performance
|
||||||
|
|
||||||
|
Performance of `mathieucarbou/ESPAsyncWebServer @ 3.3.23`:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
> brew install autocannon
|
||||||
|
> autocannon -c 10 -w 10 -d 20 http://192.168.4.1
|
||||||
|
```
|
||||||
|
|
||||||
|
With `mathieucarbou/AsyncTCP @ 3.2.14`
|
||||||
|
|
||||||
|
[![](https://mathieu.carbou.me/ESPAsyncWebServer/perf-c10.png)](https://mathieu.carbou.me/ESPAsyncWebServer/perf-c10.png)
|
||||||
|
|
||||||
|
With `https://github.com/mathieucarbou/AsyncTCPSock/archive/refs/tags/v1.0.3-dev.zip`:
|
||||||
|
|
||||||
|
[![](https://mathieu.carbou.me/ESPAsyncWebServer/perf-c10-asynctcpsock.png)](https://mathieu.carbou.me/ESPAsyncWebServer/perf-c10-asynctcpsock.png)
|
||||||
|
|
||||||
|
**SSE performance**
|
||||||
|
|
||||||
|
In the example, there is an endpoint `/events` with some comments showing how these metrics are calculated.
|
||||||
|
|
||||||
|
Test is running for 20 seconds with 10 connections.
|
||||||
|
|
||||||
|
```
|
||||||
|
// With AsyncTCP, with 10 workers: no message discarded from the queue
|
||||||
|
//
|
||||||
|
// Total: 1875 events, 468.75000000000000000000 events / second
|
||||||
|
// Total: 1870 events, 467.50000000000000000000 events / second
|
||||||
|
// Total: 1871 events, 467.75000000000000000000 events / second
|
||||||
|
// Total: 1875 events, 468.75000000000000000000 events / second
|
||||||
|
// Total: 1871 events, 467.75000000000000000000 events / second
|
||||||
|
// Total: 1805 events, 451.25000000000000000000 events / second
|
||||||
|
// Total: 1803 events, 450.75000000000000000000 events / second
|
||||||
|
// Total: 1873 events, 468.25000000000000000000 events / second
|
||||||
|
// Total: 1872 events, 468.00000000000000000000 events / second
|
||||||
|
// Total: 1805 events, 451.25000000000000000000 events / second
|
||||||
|
//
|
||||||
|
// With AsyncTCPSock, with 10 workers: no message discarded from the queue
|
||||||
|
//
|
||||||
|
// Total: 1242 events, 310.50000000000000000000 events / second
|
||||||
|
// Total: 1242 events, 310.50000000000000000000 events / second
|
||||||
|
// Total: 1242 events, 310.50000000000000000000 events / second
|
||||||
|
// Total: 1242 events, 310.50000000000000000000 events / second
|
||||||
|
// Total: 1181 events, 295.25000000000000000000 events / second
|
||||||
|
// Total: 1182 events, 295.50000000000000000000 events / second
|
||||||
|
// Total: 1240 events, 310.00000000000000000000 events / second
|
||||||
|
// Total: 1181 events, 295.25000000000000000000 events / second
|
||||||
|
// Total: 1181 events, 295.25000000000000000000 events / second
|
||||||
|
// Total: 1183 events, 295.75000000000000000000 events / second
|
||||||
|
```
|
||||||
|
|
||||||
## Important recommendations
|
## Important recommendations
|
||||||
|
|
||||||
Most of the crashes are caused by improper configuration of the library for the project.
|
Most of the crashes are caused by improper configuration of the library for the project.
|
||||||
@ -72,7 +166,7 @@ Here are some recommendations to avoid them.
|
|||||||
1. Set the running core to be on the same core of your application (usually core 1) `-D CONFIG_ASYNC_TCP_RUNNING_CORE=1`
|
1. Set the running core to be on the same core of your application (usually core 1) `-D CONFIG_ASYNC_TCP_RUNNING_CORE=1`
|
||||||
2. Set the stack size appropriately with `-D CONFIG_ASYNC_TCP_STACK_SIZE=16384`.
|
2. Set the stack size appropriately with `-D CONFIG_ASYNC_TCP_STACK_SIZE=16384`.
|
||||||
The default value of `16384` might be too much for your project.
|
The default value of `16384` might be too much for your project.
|
||||||
You can look at the [MycilaTaskMonitor](https://oss.carbou.me/MycilaTaskMonitor) project to monitor the stack usage.
|
You can look at the [MycilaTaskMonitor](https://mathieu.carbou.me/MycilaTaskMonitor) project to monitor the stack usage.
|
||||||
3. You can change **if you know what you are doing** the task priority with `-D CONFIG_ASYNC_TCP_PRIORITY=10`.
|
3. You can change **if you know what you are doing** the task priority with `-D CONFIG_ASYNC_TCP_PRIORITY=10`.
|
||||||
Default is `10`.
|
Default is `10`.
|
||||||
4. You can increase the queue size with `-D CONFIG_ASYNC_TCP_QUEUE_SIZE=128`.
|
4. You can increase the queue size with `-D CONFIG_ASYNC_TCP_QUEUE_SIZE=128`.
|
||||||
@ -528,7 +622,7 @@ Endpoints which consume JSON can use a special handler to get ready to use JSON
|
|||||||
#include "ArduinoJson.h"
|
#include "ArduinoJson.h"
|
||||||
|
|
||||||
AsyncCallbackJsonWebHandler* handler = new AsyncCallbackJsonWebHandler("/rest/endpoint", [](AsyncWebServerRequest *request, JsonVariant &json) {
|
AsyncCallbackJsonWebHandler* handler = new AsyncCallbackJsonWebHandler("/rest/endpoint", [](AsyncWebServerRequest *request, JsonVariant &json) {
|
||||||
JsonObject& jsonObj = json.as<JsonObject>();
|
JsonObject jsonObj = json.as<JsonObject>();
|
||||||
// ...
|
// ...
|
||||||
});
|
});
|
||||||
server.addHandler(handler);
|
server.addHandler(handler);
|
||||||
@ -1186,7 +1280,7 @@ For actual serving the file.
|
|||||||
|
|
||||||
### Param Rewrite With Matching
|
### Param Rewrite With Matching
|
||||||
|
|
||||||
It is possible to rewrite the request url with parameter matchg. Here is an example with one parameter:
|
It is possible to rewrite the request url with parameter match. Here is an example with one parameter:
|
||||||
Rewrite for example "/radio/{frequence}" -> "/radio?f={frequence}"
|
Rewrite for example "/radio/{frequence}" -> "/radio?f={frequence}"
|
||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
|
128
docs/index.md
128
docs/index.md
@ -15,8 +15,9 @@ Supports: WebSocket, SSE, Authentication, Arduino Json 7, File Upload, Static Fi
|
|||||||
|
|
||||||
This fork is based on [yubox-node-org/ESPAsyncWebServer](https://github.com/yubox-node-org/ESPAsyncWebServer) and includes all the concurrency fixes.
|
This fork is based on [yubox-node-org/ESPAsyncWebServer](https://github.com/yubox-node-org/ESPAsyncWebServer) and includes all the concurrency fixes.
|
||||||
|
|
||||||
- [Coordinate and dependencies](#coordinate-and-dependencies)
|
|
||||||
- [Changes in this fork](#changes-in-this-fork)
|
- [Changes in this fork](#changes-in-this-fork)
|
||||||
|
- [Dependencies](#dependencies)
|
||||||
|
- [Performance](#performance)
|
||||||
- [Important recommendations](#important-recommendations)
|
- [Important recommendations](#important-recommendations)
|
||||||
- [`AsyncWebSocketMessageBuffer` and `makeBuffer()`](#asyncwebsocketmessagebuffer-and-makebuffer)
|
- [`AsyncWebSocketMessageBuffer` and `makeBuffer()`](#asyncwebsocketmessagebuffer-and-makebuffer)
|
||||||
- [How to replace a response](#how-to-replace-a-response)
|
- [How to replace a response](#how-to-replace-a-response)
|
||||||
@ -25,20 +26,6 @@ This fork is based on [yubox-node-org/ESPAsyncWebServer](https://github.com/yubo
|
|||||||
- [Migration to Middleware to improve performance and memory usage](#migration-to-middleware-to-improve-performance-and-memory-usage)
|
- [Migration to Middleware to improve performance and memory usage](#migration-to-middleware-to-improve-performance-and-memory-usage)
|
||||||
- [Original Documentation](#original-documentation)
|
- [Original Documentation](#original-documentation)
|
||||||
|
|
||||||
## Coordinate and dependencies
|
|
||||||
|
|
||||||
**WARNING** The library name was changed from `ESP Async WebServer` to `ESPAsyncWebServer` as per the Arduino Lint recommendations.
|
|
||||||
|
|
||||||
```
|
|
||||||
mathieucarbou/ESPAsyncWebServer @ 3.3.7
|
|
||||||
```
|
|
||||||
|
|
||||||
Dependency:
|
|
||||||
|
|
||||||
- **ESP32**: `mathieucarbou/AsyncTCP @ 3.2.5` (Arduino IDE: [https://github.com/mathieucarbou/AsyncTCP#v3.2.5](https://github.com/mathieucarbou/AsyncTCP/releases))
|
|
||||||
- **ESP8266**: `esphome/ESPAsyncTCP-esphome @ 2.0.0` (Arduino IDE: [https://github.com/mathieucarbou/esphome-ESPAsyncTCP#v2.0.0](https://github.com/mathieucarbou/esphome-ESPAsyncTCP/releases/tag/v2.0.0))
|
|
||||||
- **RP2040**: `khoih-prog/AsyncTCP_RP2040W @ 1.2.0` (Arduino IDE: [https://github.com/khoih-prog/AsyncTCP_RP2040W#v1.2.0](https://github.com/khoih-prog/AsyncTCP_RP2040W/releases/tag/v1.2.0))
|
|
||||||
|
|
||||||
## Changes in this fork
|
## Changes in this fork
|
||||||
|
|
||||||
- (bug) A lot of bug fixes
|
- (bug) A lot of bug fixes
|
||||||
@ -55,6 +42,7 @@ Dependency:
|
|||||||
- (feat) **Resumable download** support using HEAD and bytes range
|
- (feat) **Resumable download** support using HEAD and bytes range
|
||||||
- (feat) `StreamConcat` example to show how to stream multiple files in one response
|
- (feat) `StreamConcat` example to show how to stream multiple files in one response
|
||||||
- (feat) Removed ESPIDF Editor (this is not the role of a web server library to do that - get the source files from the original repos if required)
|
- (feat) Removed ESPIDF Editor (this is not the role of a web server library to do that - get the source files from the original repos if required)
|
||||||
|
- (perf) [AsyncTCPSock](https://github.com/mathieucarbou/AsyncTCPSock) support: AsyncTCP can be ignored and AsyncTCPSock used instead
|
||||||
- (perf) `char*` overloads to avoid using `String`
|
- (perf) `char*` overloads to avoid using `String`
|
||||||
- (perf) `DEFAULT_MAX_WS_CLIENTS` to change the number of allows WebSocket clients and use `cleanupClients()` to help cleanup resources about dead clients
|
- (perf) `DEFAULT_MAX_WS_CLIENTS` to change the number of allows WebSocket clients and use `cleanupClients()` to help cleanup resources about dead clients
|
||||||
- (perf) `setCloseClientOnQueueFull(bool)` which can be set on a client to either close the connection or discard messages but not close the connection when the queue is full
|
- (perf) `setCloseClientOnQueueFull(bool)` which can be set on a client to either close the connection or discard messages but not close the connection when the queue is full
|
||||||
@ -64,6 +52,112 @@ Dependency:
|
|||||||
- (perf) Lot of code cleanup and optimizations
|
- (perf) Lot of code cleanup and optimizations
|
||||||
- (perf) Performance improvements in terms of memory, speed and size
|
- (perf) Performance improvements in terms of memory, speed and size
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## WARNING: Important notes about future version 4.x
|
||||||
|
|
||||||
|
This ESPAsyncWebServer fork is now at version 3.x.
|
||||||
|
|
||||||
|
Next version 4.x will:
|
||||||
|
|
||||||
|
1. Drop support for ESP8266, which goes EOL in a few years. All ESP8266 boards can be replaced by equivalent ESP32 boards.
|
||||||
|
2. Drop support for Arduino 2.x and ESP-IDF 4.x. The library will be compatible with Arduino 3.x and ESP-IDF 5.x.
|
||||||
|
3. Drop support for ArduinoJson 5.x and 6.x. The library will be compatible with ArduinoJson 7.x.
|
||||||
|
|
||||||
|
So if you need one of these feature, you will have to stick with 3.x or another fork.
|
||||||
|
|
||||||
|
## Dependencies
|
||||||
|
|
||||||
|
**WARNING** The library name was changed from `ESP Async WebServer` to `ESPAsyncWebServer` as per the Arduino Lint recommendations, but its name had to stay `ESP Async WebServer` in Arduino Registry.
|
||||||
|
|
||||||
|
**PlatformIO / pioarduino:**
|
||||||
|
|
||||||
|
```ini
|
||||||
|
lib_compat_mode = strict
|
||||||
|
lib_ldf_mode = chain
|
||||||
|
lib_deps = mathieucarbou/ESPAsyncWebServer @ 3.3.23
|
||||||
|
```
|
||||||
|
|
||||||
|
**Dependencies:**
|
||||||
|
|
||||||
|
- **ESP32 with AsyncTCP**: `mathieucarbou/AsyncTCP @ 3.2.14`
|
||||||
|
Arduino IDE: [https://github.com/mathieucarbou/AsyncTCP#v3.2.14](https://github.com/mathieucarbou/AsyncTCP/releases)
|
||||||
|
|
||||||
|
- **ESP32 with AsyncTCPSock**: `https://github.com/mathieucarbou/AsyncTCPSock/archive/refs/tags/v1.0.3-dev.zip`
|
||||||
|
|
||||||
|
- **ESP8266**: `esphome/ESPAsyncTCP-esphome @ 2.0.0`
|
||||||
|
Arduino IDE: [https://github.com/mathieucarbou/esphome-ESPAsyncTCP#v2.0.0](https://github.com/mathieucarbou/esphome-ESPAsyncTCP/releases/tag/v2.0.0)
|
||||||
|
|
||||||
|
- **RP2040**: `khoih-prog/AsyncTCP_RP2040W @ 1.2.0`
|
||||||
|
Arduino IDE: [https://github.com/khoih-prog/AsyncTCP_RP2040W#v1.2.0](https://github.com/khoih-prog/AsyncTCP_RP2040W/releases/tag/v1.2.0)
|
||||||
|
|
||||||
|
**AsyncTCPSock**
|
||||||
|
|
||||||
|
AsyncTCPSock can be used instead of AsyncTCP by excluding AsyncTCP from the library dependencies and adding AsyncTCPSock instead:
|
||||||
|
|
||||||
|
```ini
|
||||||
|
lib_compat_mode = strict
|
||||||
|
lib_ldf_mode = chain
|
||||||
|
lib_deps =
|
||||||
|
; mathieucarbou/AsyncTCP @ 3.2.14
|
||||||
|
https://github.com/mathieucarbou/AsyncTCPSock/archive/refs/tags/v1.0.3-dev.zip
|
||||||
|
mathieucarbou/ESPAsyncWebServer @ 3.3.23
|
||||||
|
lib_ignore =
|
||||||
|
AsyncTCP
|
||||||
|
mathieucarbou/AsyncTCP
|
||||||
|
```
|
||||||
|
|
||||||
|
## Performance
|
||||||
|
|
||||||
|
Performance of `mathieucarbou/ESPAsyncWebServer @ 3.3.23`:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
> brew install autocannon
|
||||||
|
> autocannon -c 10 -w 10 -d 20 http://192.168.4.1
|
||||||
|
```
|
||||||
|
|
||||||
|
With `mathieucarbou/AsyncTCP @ 3.2.14`
|
||||||
|
|
||||||
|
[![](https://mathieu.carbou.me/ESPAsyncWebServer/perf-c10.png)](https://mathieu.carbou.me/ESPAsyncWebServer/perf-c10.png)
|
||||||
|
|
||||||
|
With `https://github.com/mathieucarbou/AsyncTCPSock/archive/refs/tags/v1.0.3-dev.zip`:
|
||||||
|
|
||||||
|
[![](https://mathieu.carbou.me/ESPAsyncWebServer/perf-c10-asynctcpsock.png)](https://mathieu.carbou.me/ESPAsyncWebServer/perf-c10-asynctcpsock.png)
|
||||||
|
|
||||||
|
**SSE performance**
|
||||||
|
|
||||||
|
In the example, there is an endpoint `/events` with some comments showing how these metrics are calculated.
|
||||||
|
|
||||||
|
Test is running for 20 seconds with 10 connections.
|
||||||
|
|
||||||
|
```
|
||||||
|
// With AsyncTCP, with 10 workers: no message discarded from the queue
|
||||||
|
//
|
||||||
|
// Total: 1875 events, 468.75000000000000000000 events / second
|
||||||
|
// Total: 1870 events, 467.50000000000000000000 events / second
|
||||||
|
// Total: 1871 events, 467.75000000000000000000 events / second
|
||||||
|
// Total: 1875 events, 468.75000000000000000000 events / second
|
||||||
|
// Total: 1871 events, 467.75000000000000000000 events / second
|
||||||
|
// Total: 1805 events, 451.25000000000000000000 events / second
|
||||||
|
// Total: 1803 events, 450.75000000000000000000 events / second
|
||||||
|
// Total: 1873 events, 468.25000000000000000000 events / second
|
||||||
|
// Total: 1872 events, 468.00000000000000000000 events / second
|
||||||
|
// Total: 1805 events, 451.25000000000000000000 events / second
|
||||||
|
//
|
||||||
|
// With AsyncTCPSock, with 10 workers: no message discarded from the queue
|
||||||
|
//
|
||||||
|
// Total: 1242 events, 310.50000000000000000000 events / second
|
||||||
|
// Total: 1242 events, 310.50000000000000000000 events / second
|
||||||
|
// Total: 1242 events, 310.50000000000000000000 events / second
|
||||||
|
// Total: 1242 events, 310.50000000000000000000 events / second
|
||||||
|
// Total: 1181 events, 295.25000000000000000000 events / second
|
||||||
|
// Total: 1182 events, 295.50000000000000000000 events / second
|
||||||
|
// Total: 1240 events, 310.00000000000000000000 events / second
|
||||||
|
// Total: 1181 events, 295.25000000000000000000 events / second
|
||||||
|
// Total: 1181 events, 295.25000000000000000000 events / second
|
||||||
|
// Total: 1183 events, 295.75000000000000000000 events / second
|
||||||
|
```
|
||||||
|
|
||||||
## Important recommendations
|
## Important recommendations
|
||||||
|
|
||||||
Most of the crashes are caused by improper configuration of the library for the project.
|
Most of the crashes are caused by improper configuration of the library for the project.
|
||||||
@ -72,7 +166,7 @@ Here are some recommendations to avoid them.
|
|||||||
1. Set the running core to be on the same core of your application (usually core 1) `-D CONFIG_ASYNC_TCP_RUNNING_CORE=1`
|
1. Set the running core to be on the same core of your application (usually core 1) `-D CONFIG_ASYNC_TCP_RUNNING_CORE=1`
|
||||||
2. Set the stack size appropriately with `-D CONFIG_ASYNC_TCP_STACK_SIZE=16384`.
|
2. Set the stack size appropriately with `-D CONFIG_ASYNC_TCP_STACK_SIZE=16384`.
|
||||||
The default value of `16384` might be too much for your project.
|
The default value of `16384` might be too much for your project.
|
||||||
You can look at the [MycilaTaskMonitor](https://oss.carbou.me/MycilaTaskMonitor) project to monitor the stack usage.
|
You can look at the [MycilaTaskMonitor](https://mathieu.carbou.me/MycilaTaskMonitor) project to monitor the stack usage.
|
||||||
3. You can change **if you know what you are doing** the task priority with `-D CONFIG_ASYNC_TCP_PRIORITY=10`.
|
3. You can change **if you know what you are doing** the task priority with `-D CONFIG_ASYNC_TCP_PRIORITY=10`.
|
||||||
Default is `10`.
|
Default is `10`.
|
||||||
4. You can increase the queue size with `-D CONFIG_ASYNC_TCP_QUEUE_SIZE=128`.
|
4. You can increase the queue size with `-D CONFIG_ASYNC_TCP_QUEUE_SIZE=128`.
|
||||||
@ -1186,7 +1280,7 @@ For actual serving the file.
|
|||||||
|
|
||||||
### Param Rewrite With Matching
|
### Param Rewrite With Matching
|
||||||
|
|
||||||
It is possible to rewrite the request url with parameter matchg. Here is an example with one parameter:
|
It is possible to rewrite the request url with parameter match. Here is an example with one parameter:
|
||||||
Rewrite for example "/radio/{frequence}" -> "/radio?f={frequence}"
|
Rewrite for example "/radio/{frequence}" -> "/radio?f={frequence}"
|
||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
|
BIN
docs/perf-c10-asynctcpsock.png
Normal file
BIN
docs/perf-c10-asynctcpsock.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 310 KiB |
BIN
docs/perf-c10.png
Normal file
BIN
docs/perf-c10.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 295 KiB |
@ -16,10 +16,7 @@ AsyncWebServer server(80);
|
|||||||
|
|
||||||
class CaptiveRequestHandler : public AsyncWebHandler {
|
class CaptiveRequestHandler : public AsyncWebHandler {
|
||||||
public:
|
public:
|
||||||
CaptiveRequestHandler() {}
|
bool canHandle(__unused AsyncWebServerRequest* request) const override {
|
||||||
virtual ~CaptiveRequestHandler() {}
|
|
||||||
|
|
||||||
bool canHandle(__unused AsyncWebServerRequest* request) {
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,37 +0,0 @@
|
|||||||
#include "mbedtls/md5.h"
|
|
||||||
#include <Arduino.h>
|
|
||||||
#include <MD5Builder.h>
|
|
||||||
|
|
||||||
void setup() {
|
|
||||||
Serial.begin(115200);
|
|
||||||
delay(2000);
|
|
||||||
|
|
||||||
const char* data = "Hello World";
|
|
||||||
|
|
||||||
{
|
|
||||||
uint8_t md5[16];
|
|
||||||
mbedtls_md5_context _ctx;
|
|
||||||
mbedtls_md5_init(&_ctx);
|
|
||||||
mbedtls_md5_starts(&_ctx);
|
|
||||||
mbedtls_md5_update(&_ctx, (const unsigned char*)data, strlen(data));
|
|
||||||
mbedtls_md5_finish(&_ctx, md5);
|
|
||||||
char output[33];
|
|
||||||
for (int i = 0; i < 16; i++) {
|
|
||||||
sprintf_P(output + (i * 2), PSTR("%02x"), md5[i]);
|
|
||||||
}
|
|
||||||
Serial.println(String(output));
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
MD5Builder md5;
|
|
||||||
md5.begin();
|
|
||||||
md5.add(data, strlen(data);
|
|
||||||
md5.calculate();
|
|
||||||
char output[33];
|
|
||||||
md5.getChars(output);
|
|
||||||
Serial.println(String(output));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void loop() {
|
|
||||||
}
|
|
@ -18,14 +18,11 @@ AsyncWebServer server(80);
|
|||||||
|
|
||||||
class CaptiveRequestHandler : public AsyncWebHandler {
|
class CaptiveRequestHandler : public AsyncWebHandler {
|
||||||
public:
|
public:
|
||||||
CaptiveRequestHandler() {}
|
bool canHandle(__unused AsyncWebServerRequest* request) const override {
|
||||||
virtual ~CaptiveRequestHandler() {}
|
|
||||||
|
|
||||||
bool canHandle(__unused AsyncWebServerRequest* request) {
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void handleRequest(AsyncWebServerRequest* request) {
|
void handleRequest(AsyncWebServerRequest* request) override {
|
||||||
AsyncResponseStream* response = request->beginResponseStream("text/html");
|
AsyncResponseStream* response = request->beginResponseStream("text/html");
|
||||||
response->print("<!DOCTYPE html><html><head><title>Captive Portal</title></head><body>");
|
response->print("<!DOCTYPE html><html><head><title>Captive Portal</title></head><body>");
|
||||||
response->print("<p>This is out captive portal front page.</p>");
|
response->print("<p>This is out captive portal front page.</p>");
|
||||||
|
84
examples/Issue162/Issue162.ino
Normal file
84
examples/Issue162/Issue162.ino
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
/**
|
||||||
|
*
|
||||||
|
* Connect to AP and run in bash:
|
||||||
|
*
|
||||||
|
* > while true; do echo "PING"; sleep 0.1; done | websocat ws://192.168.4.1/ws
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#include <Arduino.h>
|
||||||
|
#ifdef ESP8266
|
||||||
|
#include <ESP8266WiFi.h>
|
||||||
|
#endif
|
||||||
|
#ifdef ESP32
|
||||||
|
#include <WiFi.h>
|
||||||
|
#endif
|
||||||
|
#include <ESPAsyncWebServer.h>
|
||||||
|
|
||||||
|
#include <list>
|
||||||
|
AsyncWebServer server(80);
|
||||||
|
AsyncWebSocket ws("/ws");
|
||||||
|
|
||||||
|
void onWsEvent(AsyncWebSocket* server, AsyncWebSocketClient* client, AwsEventType type, void* arg, uint8_t* data, size_t len) {
|
||||||
|
if (type == WS_EVT_CONNECT) {
|
||||||
|
Serial.printf("Client #%" PRIu32 " connected.\n", client->id());
|
||||||
|
} else if (type == WS_EVT_DISCONNECT) {
|
||||||
|
Serial.printf("Client #%" PRIu32 " disconnected.\n", client->id());
|
||||||
|
} else if (type == WS_EVT_ERROR) {
|
||||||
|
Serial.printf("Client #%" PRIu32 " error.\n", client->id());
|
||||||
|
} else if (type == WS_EVT_DATA) {
|
||||||
|
Serial.printf("Client #%" PRIu32 " len: %u\n", client->id(), len);
|
||||||
|
} else if (type == WS_EVT_PONG) {
|
||||||
|
Serial.printf("Client #%" PRIu32 " pong.\n", client->id());
|
||||||
|
} else if (type == WS_EVT_PING) {
|
||||||
|
Serial.printf("Client #%" PRIu32 " ping.\n", client->id());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
Serial.begin(115200);
|
||||||
|
|
||||||
|
WiFi.mode(WIFI_AP);
|
||||||
|
WiFi.softAP("esp-captive");
|
||||||
|
|
||||||
|
ws.onEvent(onWsEvent);
|
||||||
|
server.addHandler(&ws);
|
||||||
|
|
||||||
|
server.on("/close_all_ws_clients", HTTP_GET | HTTP_POST, [](AsyncWebServerRequest* request) {
|
||||||
|
Serial.println("Closing all WebSocket clients...");
|
||||||
|
ws.closeAll();
|
||||||
|
request->send(200, "application/json", "{\"status\":\"all clients closed\"}");
|
||||||
|
});
|
||||||
|
|
||||||
|
server.on("/", HTTP_GET, [](AsyncWebServerRequest* request) {
|
||||||
|
request->send(200, "text/html", R"rawliteral(
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head></head>
|
||||||
|
<script>
|
||||||
|
let ws = new WebSocket("ws://" + window.location.host + "/ws");
|
||||||
|
|
||||||
|
document.addEventListener("DOMContentLoaded", function () {
|
||||||
|
ws.onopen = function () {
|
||||||
|
console.log("WebSocket connected");
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
function closeAllWsClients() {
|
||||||
|
fetch("/close_all_ws_clients", {
|
||||||
|
method : "POST",
|
||||||
|
});
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
<body>
|
||||||
|
<button onclick = "closeAllWsClients()" style = "width: 200px"> ws close all</button><p></p>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
)rawliteral");
|
||||||
|
});
|
||||||
|
|
||||||
|
server.begin();
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
vTaskDelete(NULL);
|
||||||
|
}
|
127
examples/Issue85/Issue85.ino
Normal file
127
examples/Issue85/Issue85.ino
Normal file
@ -0,0 +1,127 @@
|
|||||||
|
/**
|
||||||
|
*
|
||||||
|
* Connect to AP and run in bash:
|
||||||
|
*
|
||||||
|
* > while true; do echo "PING"; sleep 0.1; done | websocat ws://192.168.4.1/ws
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#include <Arduino.h>
|
||||||
|
#ifdef ESP8266
|
||||||
|
#include <ESP8266WiFi.h>
|
||||||
|
#endif
|
||||||
|
#ifdef ESP32
|
||||||
|
#include <WiFi.h>
|
||||||
|
#endif
|
||||||
|
#include <ESPAsyncWebServer.h>
|
||||||
|
|
||||||
|
#include <list>
|
||||||
|
|
||||||
|
size_t msgCount = 0;
|
||||||
|
size_t window = 100;
|
||||||
|
std::list<uint32_t> times;
|
||||||
|
|
||||||
|
void connect_wifi() {
|
||||||
|
WiFi.mode(WIFI_AP);
|
||||||
|
WiFi.softAP("esp-captive");
|
||||||
|
|
||||||
|
// Serial.print("Connecting");
|
||||||
|
// while (WiFi.status() != WL_CONNECTED) {
|
||||||
|
// delay(500);
|
||||||
|
// Serial.print(".");
|
||||||
|
// }
|
||||||
|
// Serial.println();
|
||||||
|
|
||||||
|
// Serial.print("Connected, IP address: ");
|
||||||
|
// Serial.println(WiFi.localIP());
|
||||||
|
}
|
||||||
|
|
||||||
|
void notFound(AsyncWebServerRequest* request) {
|
||||||
|
request->send(404, "text/plain", "Not found");
|
||||||
|
}
|
||||||
|
|
||||||
|
AsyncWebServer server(80);
|
||||||
|
AsyncWebSocket ws("/ws");
|
||||||
|
|
||||||
|
// initial stack
|
||||||
|
char* stack_start;
|
||||||
|
|
||||||
|
void printStackSize() {
|
||||||
|
char stack;
|
||||||
|
Serial.print(F("stack size "));
|
||||||
|
Serial.print(stack_start - &stack);
|
||||||
|
Serial.print(F(" | Heap free:"));
|
||||||
|
Serial.print(ESP.getFreeHeap());
|
||||||
|
#ifdef ESP8266
|
||||||
|
Serial.print(F(" frag:"));
|
||||||
|
Serial.print(ESP.getHeapFragmentation());
|
||||||
|
Serial.print(F(" maxFreeBlock:"));
|
||||||
|
Serial.print(ESP.getMaxFreeBlockSize());
|
||||||
|
#endif
|
||||||
|
Serial.println();
|
||||||
|
}
|
||||||
|
|
||||||
|
void onWsEventEmpty(AsyncWebSocket* server, AsyncWebSocketClient* client, AwsEventType type, void* arg, uint8_t* data, size_t len) {
|
||||||
|
msgCount++;
|
||||||
|
Serial.printf("count: %d\n", msgCount);
|
||||||
|
|
||||||
|
times.push_back(millis());
|
||||||
|
while (times.size() > window)
|
||||||
|
times.pop_front();
|
||||||
|
if (times.size() == window)
|
||||||
|
Serial.printf("%f req/s\n", 1000.0 * window / (times.back() - times.front()));
|
||||||
|
|
||||||
|
printStackSize();
|
||||||
|
|
||||||
|
client->text("PONG");
|
||||||
|
}
|
||||||
|
|
||||||
|
void serve_upload(AsyncWebServerRequest* request, const String& filename, size_t index, uint8_t* data, size_t len, bool final) {
|
||||||
|
Serial.print("> onUpload ");
|
||||||
|
Serial.print("index: ");
|
||||||
|
Serial.print(index);
|
||||||
|
Serial.print(" len:");
|
||||||
|
Serial.print(len);
|
||||||
|
Serial.print(" final:");
|
||||||
|
Serial.print(final);
|
||||||
|
Serial.println();
|
||||||
|
}
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
char stack;
|
||||||
|
stack_start = &stack;
|
||||||
|
|
||||||
|
Serial.begin(115200);
|
||||||
|
Serial.println("\n\n\nStart");
|
||||||
|
Serial.printf("stack_start: %p\n", stack_start);
|
||||||
|
|
||||||
|
connect_wifi();
|
||||||
|
|
||||||
|
server.onNotFound(notFound);
|
||||||
|
|
||||||
|
ws.onEvent(onWsEventEmpty);
|
||||||
|
server.addHandler(&ws);
|
||||||
|
|
||||||
|
server.on("/upload", HTTP_POST, [](AsyncWebServerRequest* request) { request->send(200); }, serve_upload);
|
||||||
|
|
||||||
|
server.begin();
|
||||||
|
Serial.println("Server started");
|
||||||
|
}
|
||||||
|
|
||||||
|
String msg = "";
|
||||||
|
uint32_t count = 0;
|
||||||
|
void loop() {
|
||||||
|
// ws.cleanupClients();
|
||||||
|
// count += 1;
|
||||||
|
// // Concatenate some string, and clear it after some time
|
||||||
|
// static unsigned long millis_string = millis();
|
||||||
|
// if (millis() - millis_string > 1) {
|
||||||
|
// millis_string += 100;
|
||||||
|
// if (count % 100 == 0) {
|
||||||
|
// // printStackSize();
|
||||||
|
// // Serial.print(msg);
|
||||||
|
// msg = String();
|
||||||
|
// } else {
|
||||||
|
// msg += 'T';
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
}
|
@ -19,7 +19,7 @@
|
|||||||
|
|
||||||
#include <ESPAsyncWebServer.h>
|
#include <ESPAsyncWebServer.h>
|
||||||
|
|
||||||
#if ASYNC_JSON_SUPPORT == 1
|
#if __has_include("ArduinoJson.h")
|
||||||
#include <ArduinoJson.h>
|
#include <ArduinoJson.h>
|
||||||
#include <AsyncJson.h>
|
#include <AsyncJson.h>
|
||||||
#include <AsyncMessagePack.h>
|
#include <AsyncMessagePack.h>
|
||||||
@ -27,6 +27,80 @@
|
|||||||
|
|
||||||
#include <LittleFS.h>
|
#include <LittleFS.h>
|
||||||
|
|
||||||
|
const char* htmlContent PROGMEM = R"(
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Sample HTML</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1>Hello, World!</h1>
|
||||||
|
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Proin euismod, purus a euismod
|
||||||
|
rhoncus, urna ipsum cursus massa, eu dictum tellus justo ac justo. Quisque ullamcorper
|
||||||
|
arcu nec tortor ullamcorper, vel fermentum justo fermentum. Vivamus sed velit ut elit
|
||||||
|
accumsan congue ut ut enim. Ut eu justo eu lacus varius gravida ut a tellus. Nulla facilisi.
|
||||||
|
Integer auctor consectetur ultricies. Fusce feugiat, mi sit amet bibendum viverra, orci leo
|
||||||
|
dapibus elit, id varius sem dui id lacus.</p>
|
||||||
|
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Proin euismod, purus a euismod
|
||||||
|
rhoncus, urna ipsum cursus massa, eu dictum tellus justo ac justo. Quisque ullamcorper
|
||||||
|
arcu nec tortor ullamcorper, vel fermentum justo fermentum. Vivamus sed velit ut elit
|
||||||
|
accumsan congue ut ut enim. Ut eu justo eu lacus varius gravida ut a tellus. Nulla facilisi.
|
||||||
|
Integer auctor consectetur ultricies. Fusce feugiat, mi sit amet bibendum viverra, orci leo
|
||||||
|
dapibus elit, id varius sem dui id lacus.</p>
|
||||||
|
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Proin euismod, purus a euismod
|
||||||
|
rhoncus, urna ipsum cursus massa, eu dictum tellus justo ac justo. Quisque ullamcorper
|
||||||
|
arcu nec tortor ullamcorper, vel fermentum justo fermentum. Vivamus sed velit ut elit
|
||||||
|
accumsan congue ut ut enim. Ut eu justo eu lacus varius gravida ut a tellus. Nulla facilisi.
|
||||||
|
Integer auctor consectetur ultricies. Fusce feugiat, mi sit amet bibendum viverra, orci leo
|
||||||
|
dapibus elit, id varius sem dui id lacus.</p>
|
||||||
|
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Proin euismod, purus a euismod
|
||||||
|
rhoncus, urna ipsum cursus massa, eu dictum tellus justo ac justo. Quisque ullamcorper
|
||||||
|
arcu nec tortor ullamcorper, vel fermentum justo fermentum. Vivamus sed velit ut elit
|
||||||
|
accumsan congue ut ut enim. Ut eu justo eu lacus varius gravida ut a tellus. Nulla facilisi.
|
||||||
|
Integer auctor consectetur ultricies. Fusce feugiat, mi sit amet bibendum viverra, orci leo
|
||||||
|
dapibus elit, id varius sem dui id lacus.</p>
|
||||||
|
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Proin euismod, purus a euismod
|
||||||
|
rhoncus, urna ipsum cursus massa, eu dictum tellus justo ac justo. Quisque ullamcorper
|
||||||
|
arcu nec tortor ullamcorper, vel fermentum justo fermentum. Vivamus sed velit ut elit
|
||||||
|
accumsan congue ut ut enim. Ut eu justo eu lacus varius gravida ut a tellus. Nulla facilisi.
|
||||||
|
Integer auctor consectetur ultricies. Fusce feugiat, mi sit amet bibendum viverra, orci leo
|
||||||
|
dapibus elit, id varius sem dui id lacus.</p>
|
||||||
|
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Proin euismod, purus a euismod
|
||||||
|
rhoncus, urna ipsum cursus massa, eu dictum tellus justo ac justo. Quisque ullamcorper
|
||||||
|
arcu nec tortor ullamcorper, vel fermentum justo fermentum. Vivamus sed velit ut elit
|
||||||
|
accumsan congue ut ut enim. Ut eu justo eu lacus varius gravida ut a tellus. Nulla facilisi.
|
||||||
|
Integer auctor consectetur ultricies. Fusce feugiat, mi sit amet bibendum viverra, orci leo
|
||||||
|
dapibus elit, id varius sem dui id lacus.</p>
|
||||||
|
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Proin euismod, purus a euismod
|
||||||
|
rhoncus, urna ipsum cursus massa, eu dictum tellus justo ac justo. Quisque ullamcorper
|
||||||
|
arcu nec tortor ullamcorper, vel fermentum justo fermentum. Vivamus sed velit ut elit
|
||||||
|
accumsan congue ut ut enim. Ut eu justo eu lacus varius gravida ut a tellus. Nulla facilisi.
|
||||||
|
Integer auctor consectetur ultricies. Fusce feugiat, mi sit amet bibendum viverra, orci leo
|
||||||
|
dapibus elit, id varius sem dui id lacus.</p>
|
||||||
|
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Proin euismod, purus a euismod
|
||||||
|
rhoncus, urna ipsum cursus massa, eu dictum tellus justo ac justo. Quisque ullamcorper
|
||||||
|
arcu nec tortor ullamcorper, vel fermentum justo fermentum. Vivamus sed velit ut elit
|
||||||
|
accumsan congue ut ut enim. Ut eu justo eu lacus varius gravida ut a tellus. Nulla facilisi.
|
||||||
|
Integer auctor consectetur ultricies. Fusce feugiat, mi sit amet bibendum viverra, orci leo
|
||||||
|
dapibus elit, id varius sem dui id lacus.</p>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
)";
|
||||||
|
|
||||||
|
const size_t htmlContentLength = strlen_P(htmlContent);
|
||||||
|
|
||||||
|
const char* staticContent PROGMEM = R"(
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Sample HTML</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1>Hello, %IP%</h1>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
)";
|
||||||
|
|
||||||
AsyncWebServer server(80);
|
AsyncWebServer server(80);
|
||||||
AsyncEventSource events("/events");
|
AsyncEventSource events("/events");
|
||||||
AsyncWebSocket ws("/ws");
|
AsyncWebSocket ws("/ws");
|
||||||
@ -111,11 +185,14 @@ void notFound(AsyncWebServerRequest* request) {
|
|||||||
request->send(404, "text/plain", "Not found");
|
request->send(404, "text/plain", "Not found");
|
||||||
}
|
}
|
||||||
|
|
||||||
#if ASYNC_JSON_SUPPORT == 1
|
#if __has_include("ArduinoJson.h")
|
||||||
AsyncCallbackJsonWebHandler* jsonHandler = new AsyncCallbackJsonWebHandler("/json2");
|
AsyncCallbackJsonWebHandler* jsonHandler = new AsyncCallbackJsonWebHandler("/json2");
|
||||||
AsyncCallbackMessagePackWebHandler* msgPackHandler = new AsyncCallbackMessagePackWebHandler("/msgpack2");
|
AsyncCallbackMessagePackWebHandler* msgPackHandler = new AsyncCallbackMessagePackWebHandler("/msgpack2");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
static const char characters[] = "0123456789ABCDEF";
|
||||||
|
static size_t charactersIndex = 0;
|
||||||
|
|
||||||
void setup() {
|
void setup() {
|
||||||
|
|
||||||
Serial.begin(115200);
|
Serial.begin(115200);
|
||||||
@ -134,6 +211,32 @@ void setup() {
|
|||||||
WiFi.softAP("esp-captive");
|
WiFi.softAP("esp-captive");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef ESP32
|
||||||
|
LittleFS.begin(true);
|
||||||
|
#else
|
||||||
|
LittleFS.begin();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
{
|
||||||
|
File f = LittleFS.open("/index.txt", "w");
|
||||||
|
if (f) {
|
||||||
|
for (size_t c = 0; c < sizeof(characters); c++) {
|
||||||
|
for (size_t i = 0; i < 1024; i++) {
|
||||||
|
f.print(characters[c]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
f.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
File f = LittleFS.open("/index.html", "w");
|
||||||
|
if (f) {
|
||||||
|
f.print(staticContent);
|
||||||
|
f.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// curl -v -X GET http://192.168.4.1/handler-not-sending-response
|
// curl -v -X GET http://192.168.4.1/handler-not-sending-response
|
||||||
server.on("/handler-not-sending-response", HTTP_GET, [](AsyncWebServerRequest* request) {
|
server.on("/handler-not-sending-response", HTTP_GET, [](AsyncWebServerRequest* request) {
|
||||||
// handler forgot to send a response to the client => 501 Not Implemented
|
// handler forgot to send a response to the client => 501 Not Implemented
|
||||||
@ -215,16 +318,18 @@ void setup() {
|
|||||||
headerFree.keep("X-Keep-Me");
|
headerFree.keep("X-Keep-Me");
|
||||||
headerFree.keep("host");
|
headerFree.keep("host");
|
||||||
|
|
||||||
// global middleware
|
|
||||||
server.addMiddleware(&requestLogger);
|
|
||||||
server.addMiddlewares({&rateLimit, &cors, &headerFilter});
|
|
||||||
|
|
||||||
cors.setOrigin("http://192.168.4.1");
|
cors.setOrigin("http://192.168.4.1");
|
||||||
cors.setMethods("POST, GET, OPTIONS, DELETE");
|
cors.setMethods("POST, GET, OPTIONS, DELETE");
|
||||||
cors.setHeaders("X-Custom-Header");
|
cors.setHeaders("X-Custom-Header");
|
||||||
cors.setAllowCredentials(false);
|
cors.setAllowCredentials(false);
|
||||||
cors.setMaxAge(600);
|
cors.setMaxAge(600);
|
||||||
|
|
||||||
|
#ifndef PERF_TEST
|
||||||
|
// global middleware
|
||||||
|
server.addMiddleware(&requestLogger);
|
||||||
|
server.addMiddlewares({&rateLimit, &cors, &headerFilter});
|
||||||
|
#endif
|
||||||
|
|
||||||
// Test CORS preflight request
|
// Test CORS preflight request
|
||||||
// curl -v -X OPTIONS -H "origin: http://192.168.4.1" http://192.168.4.1/middleware/cors
|
// curl -v -X OPTIONS -H "origin: http://192.168.4.1" http://192.168.4.1/middleware/cors
|
||||||
server.on("/middleware/cors", HTTP_GET, [](AsyncWebServerRequest* request) {
|
server.on("/middleware/cors", HTTP_GET, [](AsyncWebServerRequest* request) {
|
||||||
@ -299,12 +404,103 @@ void setup() {
|
|||||||
request->redirect("/");
|
request->redirect("/");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// PERF TEST:
|
||||||
|
// > brew install autocannon
|
||||||
|
// > autocannon -c 10 -w 10 -d 20 http://192.168.4.1
|
||||||
server.on("/", HTTP_GET, [](AsyncWebServerRequest* request) {
|
server.on("/", HTTP_GET, [](AsyncWebServerRequest* request) {
|
||||||
request->send(200, "text/plain", "Hello, world");
|
request->send(200, "text/html", htmlContent);
|
||||||
});
|
});
|
||||||
|
|
||||||
server.on("/file", HTTP_GET, [](AsyncWebServerRequest* request) {
|
// curl -v -X GET http://192.168.4.1/index.txt
|
||||||
request->send(LittleFS, "/index.html");
|
server.serveStatic("/index.txt", LittleFS, "/index.txt");
|
||||||
|
|
||||||
|
// curl -v -X GET http://192.168.4.1/index-private.txt
|
||||||
|
server.serveStatic("/index-private.txt", LittleFS, "/index.txt").setAuthentication("admin", "admin");
|
||||||
|
|
||||||
|
// ServeStatic static is used to serve static output which never changes over time.
|
||||||
|
// This special endpoints automatyically adds caching headers.
|
||||||
|
// If a template processor is used, it must enure that the outputed content will always be the ame over time and never changes.
|
||||||
|
// Otherwise, do not use serveStatic.
|
||||||
|
// Example below: IP never changes.
|
||||||
|
// curl -v -X GET http://192.168.4.1/index-static.html
|
||||||
|
server.serveStatic("/index-static.html", LittleFS, "/index.html").setTemplateProcessor([](const String& var) -> String {
|
||||||
|
if (var == "IP") {
|
||||||
|
// for CI, commented out since H2 board doesn ot support WiFi
|
||||||
|
// return WiFi.localIP().toString();
|
||||||
|
// return WiFi.softAPIP().toString();
|
||||||
|
return "127.0.0..1";
|
||||||
|
}
|
||||||
|
return emptyString;
|
||||||
|
});
|
||||||
|
|
||||||
|
// to serve a template with dynamic content (output changes over time), use normal
|
||||||
|
// Example below: content changes over tinme do not use serveStatic.
|
||||||
|
// curl -v -X GET http://192.168.4.1/index-dynamic.html
|
||||||
|
server.on("/index-dynamic.html", HTTP_GET, [](AsyncWebServerRequest* request) {
|
||||||
|
request->send(LittleFS, "/index.html", "text/html", false, [](const String& var) -> String {
|
||||||
|
if (var == "IP")
|
||||||
|
return String(random(0, 1000));
|
||||||
|
return emptyString;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// Issue #14: assert failed: tcp_update_rcv_ann_wnd (needs help to test fix)
|
||||||
|
// > curl -v http://192.168.4.1/issue-14
|
||||||
|
pinMode(4, OUTPUT);
|
||||||
|
server.on("/issue-14", HTTP_GET, [](AsyncWebServerRequest* request) {
|
||||||
|
digitalWrite(4, HIGH);
|
||||||
|
request->send(LittleFS, "/index.txt", "text/pain");
|
||||||
|
delay(500);
|
||||||
|
digitalWrite(4, LOW);
|
||||||
|
});
|
||||||
|
|
||||||
|
/*
|
||||||
|
Chunked encoding test: sends 16k of characters.
|
||||||
|
❯ curl -N -v -X GET -H "origin: http://192.168.4.1" http://192.168.4.1/chunk
|
||||||
|
*/
|
||||||
|
server.on("/chunk", HTTP_HEAD | HTTP_GET, [](AsyncWebServerRequest* request) {
|
||||||
|
AsyncWebServerResponse* response = request->beginChunkedResponse("text/html", [](uint8_t* buffer, size_t maxLen, size_t index) -> size_t {
|
||||||
|
if (index >= 16384)
|
||||||
|
return 0;
|
||||||
|
memset(buffer, characters[charactersIndex], maxLen);
|
||||||
|
charactersIndex = (charactersIndex + 1) % sizeof(characters);
|
||||||
|
return maxLen;
|
||||||
|
});
|
||||||
|
request->send(response);
|
||||||
|
});
|
||||||
|
|
||||||
|
// curl -N -v -X GET http://192.168.4.1/chunked.html --output -
|
||||||
|
// curl -N -v -X GET -H "if-none-match: 4272" http://192.168.4.1/chunked.html --output -
|
||||||
|
server.on("/chunked.html", HTTP_GET, [](AsyncWebServerRequest* request) {
|
||||||
|
String len = String(htmlContentLength);
|
||||||
|
|
||||||
|
if (request->header(asyncsrv::T_INM) == len) {
|
||||||
|
request->send(304);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
AsyncWebServerResponse* response = request->beginChunkedResponse("text/html", [](uint8_t* buffer, size_t maxLen, size_t index) -> size_t {
|
||||||
|
Serial.printf("%u / %u\n", index, htmlContentLength);
|
||||||
|
|
||||||
|
// finished ?
|
||||||
|
if (htmlContentLength <= index) {
|
||||||
|
Serial.println("finished");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// serve a maximum of 1024 or maxLen bytes of the remaining content
|
||||||
|
const int chunkSize = min((size_t)1024, min(maxLen, htmlContentLength - index));
|
||||||
|
Serial.printf("sending: %u\n", chunkSize);
|
||||||
|
|
||||||
|
memcpy(buffer, htmlContent + index, chunkSize);
|
||||||
|
|
||||||
|
return chunkSize;
|
||||||
|
});
|
||||||
|
|
||||||
|
response->addHeader(asyncsrv::T_Cache_Control, "public,max-age=60");
|
||||||
|
response->addHeader(asyncsrv::T_ETag, len);
|
||||||
|
|
||||||
|
request->send(response);
|
||||||
});
|
});
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -353,14 +549,12 @@ void setup() {
|
|||||||
request->send(200, "text/plain", "Hello, POST: " + message);
|
request->send(200, "text/plain", "Hello, POST: " + message);
|
||||||
});
|
});
|
||||||
|
|
||||||
#if ASYNC_JSON_SUPPORT == 1
|
#if __has_include("ArduinoJson.h")
|
||||||
// JSON
|
// JSON
|
||||||
|
|
||||||
// receives JSON and sends JSON
|
// sends JSON
|
||||||
jsonHandler->onRequest([](AsyncWebServerRequest* request, JsonVariant& json) {
|
// curl -v -X GET http://192.168.4.1/json1
|
||||||
// JsonObject jsonObj = json.as<JsonObject>();
|
server.on("/json1", HTTP_GET, [](AsyncWebServerRequest* request) {
|
||||||
// ...
|
|
||||||
|
|
||||||
AsyncJsonResponse* response = new AsyncJsonResponse();
|
AsyncJsonResponse* response = new AsyncJsonResponse();
|
||||||
JsonObject root = response->getRoot().to<JsonObject>();
|
JsonObject root = response->getRoot().to<JsonObject>();
|
||||||
root["hello"] = "world";
|
root["hello"] = "world";
|
||||||
@ -368,11 +562,24 @@ void setup() {
|
|||||||
request->send(response);
|
request->send(response);
|
||||||
});
|
});
|
||||||
|
|
||||||
// sends JSON
|
// curl -v -X GET http://192.168.4.1/json2
|
||||||
server.on("/json1", HTTP_GET, [](AsyncWebServerRequest* request) {
|
server.on("/json2", HTTP_GET, [](AsyncWebServerRequest* request) {
|
||||||
|
AsyncResponseStream* response = request->beginResponseStream("application/json");
|
||||||
|
JsonDocument doc;
|
||||||
|
JsonObject root = doc.to<JsonObject>();
|
||||||
|
root["foo"] = "bar";
|
||||||
|
serializeJson(root, *response);
|
||||||
|
request->send(response);
|
||||||
|
});
|
||||||
|
|
||||||
|
// curl -v -X POST -H 'Content-Type: application/json' -d '{"name":"You"}' http://192.168.4.1/json2
|
||||||
|
// curl -v -X PUT -H 'Content-Type: application/json' -d '{"name":"You"}' http://192.168.4.1/json2
|
||||||
|
jsonHandler->setMethod(HTTP_POST | HTTP_PUT);
|
||||||
|
jsonHandler->onRequest([](AsyncWebServerRequest* request, JsonVariant& json) {
|
||||||
|
serializeJson(json, Serial);
|
||||||
AsyncJsonResponse* response = new AsyncJsonResponse();
|
AsyncJsonResponse* response = new AsyncJsonResponse();
|
||||||
JsonObject root = response->getRoot().to<JsonObject>();
|
JsonObject root = response->getRoot().to<JsonObject>();
|
||||||
root["hello"] = "world";
|
root["hello"] = json.as<JsonObject>()["name"];
|
||||||
response->setLength();
|
response->setLength();
|
||||||
request->send(response);
|
request->send(response);
|
||||||
});
|
});
|
||||||
@ -436,10 +643,69 @@ void setup() {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// SSS endpoints
|
||||||
|
// sends a message every 10 ms
|
||||||
|
//
|
||||||
|
// go to http://192.168.4.1/sse
|
||||||
|
// > curl -v -N -H "Accept: text/event-stream" http://192.168.4.1/events
|
||||||
|
//
|
||||||
|
// some perf tests:
|
||||||
|
// launch 16 concurrent workers for 30 seconds
|
||||||
|
// > for i in {1..16}; do ( count=$(gtimeout 30 curl -s -N -H "Accept: text/event-stream" http://192.168.4.1/events 2>&1 | grep -c "^data:"); echo "Total: $count events, $(echo "$count / 4" | bc -l) events / second" ) & done;
|
||||||
|
//
|
||||||
|
// With AsyncTCP, with 16 workers: a lot of Too many messages queued: deleting message
|
||||||
|
//
|
||||||
|
// Total: 119 events, 29.75000000000000000000 events / second
|
||||||
|
// Total: 727 events, 181.75000000000000000000 events / second
|
||||||
|
// Total: 1386 events, 346.50000000000000000000 events / second
|
||||||
|
// Total: 1385 events, 346.25000000000000000000 events / second
|
||||||
|
// Total: 1276 events, 319.00000000000000000000 events / second
|
||||||
|
// Total: 1411 events, 352.75000000000000000000 events / second
|
||||||
|
// Total: 1276 events, 319.00000000000000000000 events / second
|
||||||
|
// Total: 1333 events, 333.25000000000000000000 events / second
|
||||||
|
// Total: 1250 events, 312.50000000000000000000 events / second
|
||||||
|
// Total: 1275 events, 318.75000000000000000000 events / second
|
||||||
|
// Total: 1271 events, 317.75000000000000000000 events / second
|
||||||
|
// Total: 1271 events, 317.75000000000000000000 events / second
|
||||||
|
// Total: 1254 events, 313.50000000000000000000 events / second
|
||||||
|
// Total: 1251 events, 312.75000000000000000000 events / second
|
||||||
|
// Total: 1254 events, 313.50000000000000000000 events / second
|
||||||
|
// Total: 1262 events, 315.50000000000000000000 events / second
|
||||||
|
//
|
||||||
|
// With AsyncTCP, with 10 workers:
|
||||||
|
//
|
||||||
|
// Total: 1875 events, 468.75000000000000000000 events / second
|
||||||
|
// Total: 1870 events, 467.50000000000000000000 events / second
|
||||||
|
// Total: 1871 events, 467.75000000000000000000 events / second
|
||||||
|
// Total: 1875 events, 468.75000000000000000000 events / second
|
||||||
|
// Total: 1871 events, 467.75000000000000000000 events / second
|
||||||
|
// Total: 1805 events, 451.25000000000000000000 events / second
|
||||||
|
// Total: 1803 events, 450.75000000000000000000 events / second
|
||||||
|
// Total: 1873 events, 468.25000000000000000000 events / second
|
||||||
|
// Total: 1872 events, 468.00000000000000000000 events / second
|
||||||
|
// Total: 1805 events, 451.25000000000000000000 events / second
|
||||||
|
//
|
||||||
|
// With AsyncTCPSock, with 16 workers: ESP32 CRASH !!!
|
||||||
|
//
|
||||||
|
// With AsyncTCPSock, with 10 workers:
|
||||||
|
//
|
||||||
|
// Total: 1242 events, 310.50000000000000000000 events / second
|
||||||
|
// Total: 1242 events, 310.50000000000000000000 events / second
|
||||||
|
// Total: 1242 events, 310.50000000000000000000 events / second
|
||||||
|
// Total: 1242 events, 310.50000000000000000000 events / second
|
||||||
|
// Total: 1181 events, 295.25000000000000000000 events / second
|
||||||
|
// Total: 1182 events, 295.50000000000000000000 events / second
|
||||||
|
// Total: 1240 events, 310.00000000000000000000 events / second
|
||||||
|
// Total: 1181 events, 295.25000000000000000000 events / second
|
||||||
|
// Total: 1181 events, 295.25000000000000000000 events / second
|
||||||
|
// Total: 1183 events, 295.75000000000000000000 events / second
|
||||||
|
//
|
||||||
server.addHandler(&events);
|
server.addHandler(&events);
|
||||||
|
|
||||||
|
// Run: websocat ws://192.168.4.1/ws
|
||||||
server.addHandler(&ws);
|
server.addHandler(&ws);
|
||||||
|
|
||||||
#if ASYNC_JSON_SUPPORT == 1
|
#if __has_include("ArduinoJson.h")
|
||||||
server.addHandler(jsonHandler);
|
server.addHandler(jsonHandler);
|
||||||
server.addHandler(msgPackHandler);
|
server.addHandler(msgPackHandler);
|
||||||
#endif
|
#endif
|
||||||
@ -450,7 +716,7 @@ void setup() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
uint32_t lastSSE = 0;
|
uint32_t lastSSE = 0;
|
||||||
uint32_t deltaSSE = 5;
|
uint32_t deltaSSE = 10;
|
||||||
|
|
||||||
uint32_t lastWS = 0;
|
uint32_t lastWS = 0;
|
||||||
uint32_t deltaWS = 100;
|
uint32_t deltaWS = 100;
|
||||||
@ -463,9 +729,8 @@ void loop() {
|
|||||||
}
|
}
|
||||||
if (now - lastWS >= deltaWS) {
|
if (now - lastWS >= deltaWS) {
|
||||||
ws.printfAll("kp%.4f", (10.0 / 3.0));
|
ws.printfAll("kp%.4f", (10.0 / 3.0));
|
||||||
// ws.getClients
|
|
||||||
for (auto& client : ws.getClients()) {
|
for (auto& client : ws.getClients()) {
|
||||||
client.text("kp%.4f", (10.0 / 3.0));
|
client.printf("kp%.4f", (10.0 / 3.0));
|
||||||
}
|
}
|
||||||
lastWS = millis();
|
lastWS = millis();
|
||||||
}
|
}
|
||||||
|
@ -10,11 +10,13 @@
|
|||||||
#include <WebServer.h>
|
#include <WebServer.h>
|
||||||
#include <WiFi.h>
|
#include <WiFi.h>
|
||||||
#endif
|
#endif
|
||||||
#include "StreamConcat.h"
|
|
||||||
#include "StreamString.h"
|
#include <StreamString.h>
|
||||||
#include <ESPAsyncWebServer.h>
|
#include <ESPAsyncWebServer.h>
|
||||||
#include <LittleFS.h>
|
#include <LittleFS.h>
|
||||||
|
|
||||||
|
#include "StreamConcat.h"
|
||||||
|
|
||||||
DNSServer dnsServer;
|
DNSServer dnsServer;
|
||||||
AsyncWebServer server(80);
|
AsyncWebServer server(80);
|
||||||
|
|
||||||
|
@ -1,40 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <Stream.h>
|
|
||||||
|
|
||||||
class StreamString : public Stream {
|
|
||||||
public:
|
|
||||||
size_t write(const uint8_t* p, size_t n) override { return _buffer.concat(reinterpret_cast<const char*>(p), n) ? n : 0; }
|
|
||||||
size_t write(uint8_t c) override { return _buffer.concat(static_cast<char>(c)) ? 1 : 0; }
|
|
||||||
void flush() override {}
|
|
||||||
|
|
||||||
int available() override { return static_cast<int>(_buffer.length()); }
|
|
||||||
|
|
||||||
int read() override {
|
|
||||||
if (_buffer.length() == 0)
|
|
||||||
return -1;
|
|
||||||
char c = _buffer[0];
|
|
||||||
_buffer.remove(0, 1);
|
|
||||||
return c;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if defined(TARGET_RP2040)
|
|
||||||
size_t readBytes(char* buffer, size_t length) {
|
|
||||||
#else
|
|
||||||
size_t readBytes(char* buffer, size_t length) override {
|
|
||||||
#endif
|
|
||||||
if (length > _buffer.length())
|
|
||||||
length = _buffer.length();
|
|
||||||
// Don't use _str.ToCharArray() because it inserts a terminator
|
|
||||||
memcpy(buffer, _buffer.c_str(), length);
|
|
||||||
_buffer.remove(0, static_cast<unsigned int>(length));
|
|
||||||
return length;
|
|
||||||
}
|
|
||||||
|
|
||||||
int peek() override { return _buffer.length() > 0 ? _buffer[0] : -1; }
|
|
||||||
|
|
||||||
const String& buffer() const { return _buffer; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
String _buffer;
|
|
||||||
};
|
|
@ -1,107 +0,0 @@
|
|||||||
#include <DNSServer.h>
|
|
||||||
#ifdef ESP32
|
|
||||||
#include <AsyncTCP.h>
|
|
||||||
#include <WiFi.h>
|
|
||||||
#elif defined(ESP8266)
|
|
||||||
#include <ESP8266WiFi.h>
|
|
||||||
#include <ESPAsyncTCP.h>
|
|
||||||
#elif defined(TARGET_RP2040)
|
|
||||||
#include <WebServer.h>
|
|
||||||
#include <WiFi.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "ESPAsyncWebServer.h"
|
|
||||||
|
|
||||||
const char appWebPage[] PROGMEM = R"rawliteral(
|
|
||||||
<body>
|
|
||||||
<button id="button1" onclick="fetch('/button1');">Relay1</button>
|
|
||||||
<script>
|
|
||||||
const evtSource = new EventSource("/events");
|
|
||||||
button1 = document.getElementById("button1");
|
|
||||||
evtSource.addEventListener('state', (e) => {
|
|
||||||
const data = JSON.parse(e.data);
|
|
||||||
console.log('Event Source data: ', data);
|
|
||||||
if (data.button1) {
|
|
||||||
button1.style.backgroundColor = "green";
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
button1.style.backgroundColor = "red";
|
|
||||||
}
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
</body>
|
|
||||||
)rawliteral";
|
|
||||||
|
|
||||||
AsyncWebServer server(80);
|
|
||||||
AsyncEventSource events("/events");
|
|
||||||
|
|
||||||
const uint32_t interval = 1000;
|
|
||||||
const int button1Pin = 4;
|
|
||||||
|
|
||||||
uint32_t lastSend = 0;
|
|
||||||
|
|
||||||
void prepareJson(String& buffer) {
|
|
||||||
buffer.reserve(512);
|
|
||||||
buffer.concat("{\"button1\":");
|
|
||||||
buffer.concat(digitalRead(button1Pin) == LOW);
|
|
||||||
buffer.concat(",\"1234567890abcdefghij1234567890abcdefghij1234567890abcdefghij1234567890abcdefghij1234567890abcdefghij1234567890abcdefghij\":");
|
|
||||||
buffer.concat(random(0, 999999999));
|
|
||||||
buffer.concat("}");
|
|
||||||
}
|
|
||||||
|
|
||||||
void setup() {
|
|
||||||
Serial.begin(115200);
|
|
||||||
#if ARDUINO_USB_CDC_ON_BOOT
|
|
||||||
Serial.setTxTimeoutMs(0);
|
|
||||||
delay(100);
|
|
||||||
#else
|
|
||||||
while (!Serial)
|
|
||||||
yield();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
randomSeed(micros());
|
|
||||||
|
|
||||||
pinMode(button1Pin, OUTPUT);
|
|
||||||
digitalWrite(button1Pin, HIGH);
|
|
||||||
|
|
||||||
WiFi.softAP("esp-captive");
|
|
||||||
|
|
||||||
server.on("/", HTTP_GET, [](AsyncWebServerRequest* request) {
|
|
||||||
request->send(200, "text/html", appWebPage);
|
|
||||||
});
|
|
||||||
|
|
||||||
server.on("/button1", HTTP_GET, [](AsyncWebServerRequest* request) {
|
|
||||||
request->send(200, "text/plain", "OK");
|
|
||||||
digitalWrite(button1Pin, digitalRead(button1Pin) == LOW ? HIGH : LOW);
|
|
||||||
|
|
||||||
String buffer;
|
|
||||||
prepareJson(buffer);
|
|
||||||
ESP_LOGI("async_tcp", "Sending from handler...");
|
|
||||||
events.send(buffer.c_str(), "state", millis());
|
|
||||||
ESP_LOGI("async_tcp", "Sent from handler!");
|
|
||||||
});
|
|
||||||
|
|
||||||
events.onConnect([](AsyncEventSourceClient* client) {
|
|
||||||
String buffer;
|
|
||||||
prepareJson(buffer);
|
|
||||||
ESP_LOGI("async_tcp", "Sending from onConnect...");
|
|
||||||
client->send(buffer.c_str(), "state", millis(), 5000);
|
|
||||||
ESP_LOGI("async_tcp", "Sent from onConnect!");
|
|
||||||
});
|
|
||||||
|
|
||||||
server.addHandler(&events);
|
|
||||||
DefaultHeaders::Instance().addHeader("Access-Control-Allow-Origin", "*");
|
|
||||||
|
|
||||||
server.begin();
|
|
||||||
}
|
|
||||||
|
|
||||||
void loop() {
|
|
||||||
if (millis() - lastSend >= interval) {
|
|
||||||
String buffer;
|
|
||||||
prepareJson(buffer);
|
|
||||||
ESP_LOGI("loop", "Sending...");
|
|
||||||
events.send(buffer.c_str(), "state", millis());
|
|
||||||
ESP_LOGI("loop", "Sent!");
|
|
||||||
lastSend = millis();
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "ESPAsyncWebServer",
|
"name": "ESPAsyncWebServer",
|
||||||
"version": "3.3.7",
|
"version": "3.3.23",
|
||||||
"description": "Asynchronous HTTP and WebSocket Server Library for ESP32, ESP8266 and RP2040. Supports: WebSocket, SSE, Authentication, Arduino Json 7, File Upload, Static File serving, URL Rewrite, URL Redirect, etc.",
|
"description": "Asynchronous HTTP and WebSocket Server Library for ESP32, ESP8266 and RP2040. Supports: WebSocket, SSE, Authentication, Arduino Json 7, File Upload, Static File serving, URL Rewrite, URL Redirect, etc.",
|
||||||
"keywords": "http,async,websocket,webserver",
|
"keywords": "http,async,websocket,webserver",
|
||||||
"homepage": "https://github.com/mathieucarbou/ESPAsyncWebServer",
|
"homepage": "https://github.com/mathieucarbou/ESPAsyncWebServer",
|
||||||
@ -28,7 +28,7 @@
|
|||||||
{
|
{
|
||||||
"owner": "mathieucarbou",
|
"owner": "mathieucarbou",
|
||||||
"name": "AsyncTCP",
|
"name": "AsyncTCP",
|
||||||
"version": "^3.2.5",
|
"version": "^3.2.14",
|
||||||
"platforms": "espressif32"
|
"platforms": "espressif32"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
name=ESP Async WebServer
|
name=ESP Async WebServer
|
||||||
version=3.3.7
|
includes=ESPAsyncWebServer.h
|
||||||
|
version=3.3.23
|
||||||
author=Me-No-Dev
|
author=Me-No-Dev
|
||||||
maintainer=Mathieu Carbou <mathieu.carbou@gmail.com>
|
maintainer=Mathieu Carbou <mathieu.carbou@gmail.com>
|
||||||
sentence=Asynchronous HTTP and WebSocket Server Library for ESP32, ESP8266 and RP2040
|
sentence=Asynchronous HTTP and WebSocket Server Library for ESP32, ESP8266 and RP2040
|
||||||
|
7
partitions-4MB.csv
Normal file
7
partitions-4MB.csv
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
# Name ,Type ,SubType ,Offset ,Size ,Flags
|
||||||
|
nvs ,data ,nvs ,36K ,20K ,
|
||||||
|
otadata ,data ,ota ,56K ,8K ,
|
||||||
|
app0 ,app ,ota_0 ,64K ,1856K ,
|
||||||
|
app1 ,app ,ota_1 ,1920K ,1856K ,
|
||||||
|
spiffs ,data ,spiffs ,3776K ,256K ,
|
||||||
|
coredump ,data ,coredump ,4032K ,64K ,
|
|
@ -1,16 +1,17 @@
|
|||||||
[platformio]
|
[platformio]
|
||||||
default_envs = arduino-2, arduino-3, arduino-310rc1, esp8266, raspberrypi
|
default_envs = arduino-2, arduino-3, arduino-310, esp8266, raspberrypi
|
||||||
lib_dir = .
|
lib_dir = .
|
||||||
; src_dir = examples/CaptivePortal
|
; src_dir = examples/CaptivePortal
|
||||||
src_dir = examples/SimpleServer
|
; src_dir = examples/SimpleServer
|
||||||
; src_dir = examples/StreamFiles
|
; src_dir = examples/StreamFiles
|
||||||
; src_dir = examples/Filters
|
; src_dir = examples/Filters
|
||||||
; src_dir = examples/Draft
|
; src_dir = examples/Issue85
|
||||||
; src_dir = examples/issues/Issue14
|
src_dir = examples/Issue162
|
||||||
|
|
||||||
[env]
|
[env]
|
||||||
framework = arduino
|
framework = arduino
|
||||||
build_flags =
|
build_flags =
|
||||||
|
-Og
|
||||||
-Wall -Wextra
|
-Wall -Wextra
|
||||||
-Wno-unused-parameter
|
-Wno-unused-parameter
|
||||||
-D CONFIG_ARDUHAL_LOG_COLORS
|
-D CONFIG_ARDUHAL_LOG_COLORS
|
||||||
@ -23,12 +24,17 @@ build_flags =
|
|||||||
upload_protocol = esptool
|
upload_protocol = esptool
|
||||||
monitor_speed = 115200
|
monitor_speed = 115200
|
||||||
monitor_filters = esp32_exception_decoder, log2file
|
monitor_filters = esp32_exception_decoder, log2file
|
||||||
|
; monitor_filters = esp8266_exception_decoder, log2file
|
||||||
|
lib_compat_mode = strict
|
||||||
|
lib_ldf_mode = chain
|
||||||
lib_deps =
|
lib_deps =
|
||||||
; bblanchon/ArduinoJson @ 5.13.4
|
; bblanchon/ArduinoJson @ 5.13.4
|
||||||
; bblanchon/ArduinoJson @ 6.21.5
|
; bblanchon/ArduinoJson @ 6.21.5
|
||||||
bblanchon/ArduinoJson @ 7.2.0
|
bblanchon/ArduinoJson @ 7.2.1
|
||||||
mathieucarbou/AsyncTCP @ 3.2.5
|
mathieucarbou/AsyncTCP @ 3.2.14
|
||||||
board = esp32dev
|
board = esp32dev
|
||||||
|
board_build.partitions = partitions-4MB.csv
|
||||||
|
board_build.filesystem = littlefs
|
||||||
|
|
||||||
[env:arduino-2]
|
[env:arduino-2]
|
||||||
platform = espressif32@6.9.0
|
platform = espressif32@6.9.0
|
||||||
@ -43,33 +49,42 @@ platform = https://github.com/pioarduino/platform-espressif32/releases/download/
|
|||||||
; board = esp32-s3-devkitc-1
|
; board = esp32-s3-devkitc-1
|
||||||
; board = esp32-c6-devkitc-1
|
; board = esp32-c6-devkitc-1
|
||||||
lib_deps =
|
lib_deps =
|
||||||
mathieucarbou/AsyncTCP @ 3.2.5
|
mathieucarbou/AsyncTCP @ 3.2.14
|
||||||
|
|
||||||
[env:arduino-310rc1]
|
[env:arduino-310]
|
||||||
platform = https://github.com/pioarduino/platform-espressif32/releases/download/53.03.10-rc1/platform-espressif32.zip
|
platform = https://github.com/pioarduino/platform-espressif32/releases/download/53.03.10-rc3/platform-espressif32.zip
|
||||||
; board = esp32-s3-devkitc-1
|
; board = esp32-s3-devkitc-1
|
||||||
; board = esp32-c6-devkitc-1
|
; board = esp32-c6-devkitc-1
|
||||||
|
; board = esp32-h2-devkitm-1
|
||||||
|
|
||||||
|
[env:perf-test-AsyncTCP]
|
||||||
|
platform = https://github.com/pioarduino/platform-espressif32/releases/download/53.03.10-rc3/platform-espressif32.zip
|
||||||
|
build_flags = ${env.build_flags}
|
||||||
|
-D PERF_TEST=1
|
||||||
|
|
||||||
|
[env:perf-test-AsyncTCPSock]
|
||||||
|
platform = https://github.com/pioarduino/platform-espressif32/releases/download/53.03.10-rc3/platform-espressif32.zip
|
||||||
|
lib_deps =
|
||||||
|
https://github.com/mathieucarbou/AsyncTCPSock/archive/refs/tags/v1.0.3-dev.zip
|
||||||
|
build_flags = ${env.build_flags}
|
||||||
|
-D PERF_TEST=1
|
||||||
|
|
||||||
[env:esp8266]
|
[env:esp8266]
|
||||||
platform = espressif8266
|
platform = espressif8266
|
||||||
board = huzzah
|
; board = huzzah
|
||||||
; board = d1_mini
|
board = d1_mini
|
||||||
lib_deps =
|
lib_deps =
|
||||||
bblanchon/ArduinoJson @ 7.2.0
|
bblanchon/ArduinoJson @ 7.2.1
|
||||||
esphome/ESPAsyncTCP-esphome @ 2.0.0
|
esphome/ESPAsyncTCP-esphome @ 2.0.0
|
||||||
|
|
||||||
; PlatformIO support for Raspberry Pi Pico is not official
|
|
||||||
; https://github.com/platformio/platform-raspberrypi/pull/36
|
|
||||||
; https://github.com/earlephilhower/arduino-pico/blob/master/docs/platformio.rst
|
|
||||||
; board settings: https://github.com/earlephilhower/arduino-pico/blob/master/tools/json/rpipico.json
|
|
||||||
[env:raspberrypi]
|
[env:raspberrypi]
|
||||||
upload_protocol = picotool
|
platform = https://github.com/maxgerhardt/platform-raspberrypi.git
|
||||||
; platform = raspberrypi
|
|
||||||
platform = https://github.com/maxgerhardt/platform-raspberrypi.git#f2687073f73d554c9db41f29b4769fd9703f4e55
|
|
||||||
board = rpipicow
|
board = rpipicow
|
||||||
lib_deps =
|
lib_deps =
|
||||||
bblanchon/ArduinoJson @ 7.2.0
|
bblanchon/ArduinoJson @ 7.2.1
|
||||||
khoih-prog/AsyncTCP_RP2040W @ 1.2.0
|
khoih-prog/AsyncTCP_RP2040W @ 1.2.0
|
||||||
|
lib_ignore =
|
||||||
|
lwIP_ESPHost
|
||||||
build_flags = ${env.build_flags}
|
build_flags = ${env.build_flags}
|
||||||
-Wno-missing-field-initializers
|
-Wno-missing-field-initializers
|
||||||
|
|
||||||
@ -87,25 +102,26 @@ board = ${sysenv.PIO_BOARD}
|
|||||||
platform = https://github.com/pioarduino/platform-espressif32/releases/download/51.03.05/platform-espressif32.zip
|
platform = https://github.com/pioarduino/platform-espressif32/releases/download/51.03.05/platform-espressif32.zip
|
||||||
board = ${sysenv.PIO_BOARD}
|
board = ${sysenv.PIO_BOARD}
|
||||||
lib_deps =
|
lib_deps =
|
||||||
mathieucarbou/AsyncTCP @ 3.2.5
|
mathieucarbou/AsyncTCP @ 3.2.14
|
||||||
|
|
||||||
[env:ci-arduino-310rc1]
|
[env:ci-arduino-310]
|
||||||
platform = https://github.com/pioarduino/platform-espressif32/releases/download/53.03.10-rc1/platform-espressif32.zip
|
platform = https://github.com/pioarduino/platform-espressif32/releases/download/53.03.10-rc3/platform-espressif32.zip
|
||||||
board = ${sysenv.PIO_BOARD}
|
board = ${sysenv.PIO_BOARD}
|
||||||
|
|
||||||
[env:ci-esp8266]
|
[env:ci-esp8266]
|
||||||
platform = espressif8266
|
platform = espressif8266
|
||||||
board = ${sysenv.PIO_BOARD}
|
board = ${sysenv.PIO_BOARD}
|
||||||
lib_deps =
|
lib_deps =
|
||||||
bblanchon/ArduinoJson @ 7.2.0
|
bblanchon/ArduinoJson @ 7.2.1
|
||||||
esphome/ESPAsyncTCP-esphome @ 2.0.0
|
esphome/ESPAsyncTCP-esphome @ 2.0.0
|
||||||
|
|
||||||
[env:ci-raspberrypi]
|
[env:ci-raspberrypi]
|
||||||
; platform = raspberrypi
|
platform = https://github.com/maxgerhardt/platform-raspberrypi.git
|
||||||
platform = https://github.com/maxgerhardt/platform-raspberrypi.git#f2687073f73d554c9db41f29b4769fd9703f4e55
|
|
||||||
board = ${sysenv.PIO_BOARD}
|
board = ${sysenv.PIO_BOARD}
|
||||||
lib_deps =
|
lib_deps =
|
||||||
bblanchon/ArduinoJson @ 7.2.0
|
bblanchon/ArduinoJson @ 7.2.1
|
||||||
khoih-prog/AsyncTCP_RP2040W @ 1.2.0
|
khoih-prog/AsyncTCP_RP2040W @ 1.2.0
|
||||||
|
lib_ignore =
|
||||||
|
lwIP_ESPHost
|
||||||
build_flags = ${env.build_flags}
|
build_flags = ${env.build_flags}
|
||||||
-Wno-missing-field-initializers
|
-Wno-missing-field-initializers
|
||||||
|
@ -141,6 +141,9 @@ size_t AsyncEventSourceMessage::ack(size_t len, __attribute__((unused)) uint32_t
|
|||||||
}
|
}
|
||||||
|
|
||||||
size_t AsyncEventSourceMessage::write(AsyncClient* client) {
|
size_t AsyncEventSourceMessage::write(AsyncClient* client) {
|
||||||
|
if (!client)
|
||||||
|
return 0;
|
||||||
|
|
||||||
if (_sent >= _len || !client->canSend()) {
|
if (_sent >= _len || !client->canSend()) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -186,7 +189,10 @@ AsyncEventSourceClient::~AsyncEventSourceClient() {
|
|||||||
close();
|
close();
|
||||||
}
|
}
|
||||||
|
|
||||||
void AsyncEventSourceClient::_queueMessage(const char* message, size_t len) {
|
bool AsyncEventSourceClient::_queueMessage(const char* message, size_t len) {
|
||||||
|
if (!_client)
|
||||||
|
return false;
|
||||||
|
|
||||||
#ifdef ESP32
|
#ifdef ESP32
|
||||||
// length() is not thread-safe, thus acquiring the lock before this call..
|
// length() is not thread-safe, thus acquiring the lock before this call..
|
||||||
std::lock_guard<std::mutex> lock(_lockmq);
|
std::lock_guard<std::mutex> lock(_lockmq);
|
||||||
@ -198,7 +204,7 @@ void AsyncEventSourceClient::_queueMessage(const char* message, size_t len) {
|
|||||||
#elif defined(ESP32)
|
#elif defined(ESP32)
|
||||||
log_e("Too many messages queued: deleting message");
|
log_e("Too many messages queued: deleting message");
|
||||||
#endif
|
#endif
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
_messageQueue.emplace_back(message, len);
|
_messageQueue.emplace_back(message, len);
|
||||||
@ -206,6 +212,8 @@ void AsyncEventSourceClient::_queueMessage(const char* message, size_t len) {
|
|||||||
if (_client->canSend()) {
|
if (_client->canSend()) {
|
||||||
_runQueue();
|
_runQueue();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AsyncEventSourceClient::_onAck(size_t len __attribute__((unused)), uint32_t time __attribute__((unused))) {
|
void AsyncEventSourceClient::_onAck(size_t len __attribute__((unused)), uint32_t time __attribute__((unused))) {
|
||||||
@ -227,30 +235,31 @@ void AsyncEventSourceClient::_onPoll() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void AsyncEventSourceClient::_onTimeout(uint32_t time __attribute__((unused))) {
|
void AsyncEventSourceClient::_onTimeout(uint32_t time __attribute__((unused))) {
|
||||||
|
if (_client)
|
||||||
_client->close(true);
|
_client->close(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AsyncEventSourceClient::_onDisconnect() {
|
void AsyncEventSourceClient::_onDisconnect() {
|
||||||
_client = NULL;
|
if (!_client)
|
||||||
|
return;
|
||||||
|
_client = nullptr;
|
||||||
_server->_handleDisconnect(this);
|
_server->_handleDisconnect(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AsyncEventSourceClient::close() {
|
void AsyncEventSourceClient::close() {
|
||||||
if (_client != NULL)
|
if (_client)
|
||||||
_client->close();
|
_client->close();
|
||||||
}
|
}
|
||||||
|
|
||||||
void AsyncEventSourceClient::write(const char* message, size_t len) {
|
bool AsyncEventSourceClient::write(const char* message, size_t len) {
|
||||||
if (!connected())
|
return connected() && _queueMessage(message, len);
|
||||||
return;
|
|
||||||
_queueMessage(message, len);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void AsyncEventSourceClient::send(const char* message, const char* event, uint32_t id, uint32_t reconnect) {
|
bool AsyncEventSourceClient::send(const char* message, const char* event, uint32_t id, uint32_t reconnect) {
|
||||||
if (!connected())
|
if (!connected())
|
||||||
return;
|
return false;
|
||||||
String ev = generateEventMessage(message, event, id, reconnect);
|
String ev = generateEventMessage(message, event, id, reconnect);
|
||||||
_queueMessage(ev.c_str(), ev.length());
|
return _queueMessage(ev.c_str(), ev.length());
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t AsyncEventSourceClient::packetsWaiting() const {
|
size_t AsyncEventSourceClient::packetsWaiting() const {
|
||||||
@ -261,6 +270,9 @@ size_t AsyncEventSourceClient::packetsWaiting() const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void AsyncEventSourceClient::_runQueue() {
|
void AsyncEventSourceClient::_runQueue() {
|
||||||
|
if (!_client)
|
||||||
|
return;
|
||||||
|
|
||||||
size_t total_bytes_written = 0;
|
size_t total_bytes_written = 0;
|
||||||
for (auto i = _messageQueue.begin(); i != _messageQueue.end(); ++i) {
|
for (auto i = _messageQueue.begin(); i != _messageQueue.end(); ++i) {
|
||||||
if (!i->sent()) {
|
if (!i->sent()) {
|
||||||
@ -270,6 +282,7 @@ void AsyncEventSourceClient::_runQueue() {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (total_bytes_written > 0)
|
if (total_bytes_written > 0)
|
||||||
_client->send();
|
_client->send();
|
||||||
|
|
||||||
@ -282,11 +295,6 @@ void AsyncEventSourceClient::_runQueue() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handler
|
|
||||||
void AsyncEventSource::onConnect(ArEventHandlerFunction cb) {
|
|
||||||
_connectcb = cb;
|
|
||||||
}
|
|
||||||
|
|
||||||
void AsyncEventSource::authorizeConnect(ArAuthorizeConnectHandler cb) {
|
void AsyncEventSource::authorizeConnect(ArAuthorizeConnectHandler cb) {
|
||||||
AuthorizationMiddleware* m = new AuthorizationMiddleware(401, cb);
|
AuthorizationMiddleware* m = new AuthorizationMiddleware(401, cb);
|
||||||
m->_freeOnRemoval = true;
|
m->_freeOnRemoval = true;
|
||||||
@ -308,6 +316,8 @@ void AsyncEventSource::_handleDisconnect(AsyncEventSourceClient* client) {
|
|||||||
#ifdef ESP32
|
#ifdef ESP32
|
||||||
std::lock_guard<std::mutex> lock(_client_queue_lock);
|
std::lock_guard<std::mutex> lock(_client_queue_lock);
|
||||||
#endif
|
#endif
|
||||||
|
if (_disconnectcb)
|
||||||
|
_disconnectcb(client);
|
||||||
for (auto i = _clients.begin(); i != _clients.end(); ++i) {
|
for (auto i = _clients.begin(); i != _clients.end(); ++i) {
|
||||||
if (i->get() == client)
|
if (i->get() == client)
|
||||||
_clients.erase(i);
|
_clients.erase(i);
|
||||||
@ -346,17 +356,21 @@ size_t AsyncEventSource::avgPacketsWaiting() const {
|
|||||||
return ((aql) + (nConnectedClients / 2)) / (nConnectedClients); // round up
|
return ((aql) + (nConnectedClients / 2)) / (nConnectedClients); // round up
|
||||||
}
|
}
|
||||||
|
|
||||||
void AsyncEventSource::send(
|
AsyncEventSource::SendStatus AsyncEventSource::send(
|
||||||
const char* message, const char* event, uint32_t id, uint32_t reconnect) {
|
const char* message, const char* event, uint32_t id, uint32_t reconnect) {
|
||||||
String ev = generateEventMessage(message, event, id, reconnect);
|
String ev = generateEventMessage(message, event, id, reconnect);
|
||||||
#ifdef ESP32
|
#ifdef ESP32
|
||||||
std::lock_guard<std::mutex> lock(_client_queue_lock);
|
std::lock_guard<std::mutex> lock(_client_queue_lock);
|
||||||
#endif
|
#endif
|
||||||
|
size_t hits = 0;
|
||||||
|
size_t miss = 0;
|
||||||
for (const auto& c : _clients) {
|
for (const auto& c : _clients) {
|
||||||
if (c->connected()) {
|
if (c->write(ev.c_str(), ev.length()))
|
||||||
c->write(ev.c_str(), ev.length());
|
++hits;
|
||||||
}
|
else
|
||||||
|
++miss;
|
||||||
}
|
}
|
||||||
|
return hits == 0 ? DISCARDED : (miss == 0 ? ENQUEUED : PARTIALLY_ENQUEUED);
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t AsyncEventSource::count() const {
|
size_t AsyncEventSource::count() const {
|
||||||
@ -371,11 +385,8 @@ size_t AsyncEventSource::count() const {
|
|||||||
return n_clients;
|
return n_clients;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AsyncEventSource::canHandle(AsyncWebServerRequest* request) {
|
bool AsyncEventSource::canHandle(AsyncWebServerRequest* request) const {
|
||||||
if (request->method() != HTTP_GET || !request->url().equals(_url)) {
|
return request->isSSE() && request->url().equals(_url);
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void AsyncEventSource::handleRequest(AsyncWebServerRequest* request) {
|
void AsyncEventSource::handleRequest(AsyncWebServerRequest* request) {
|
||||||
|
@ -81,7 +81,7 @@ class AsyncEventSourceClient {
|
|||||||
#ifdef ESP32
|
#ifdef ESP32
|
||||||
mutable std::mutex _lockmq;
|
mutable std::mutex _lockmq;
|
||||||
#endif
|
#endif
|
||||||
void _queueMessage(const char* message, size_t len);
|
bool _queueMessage(const char* message, size_t len);
|
||||||
void _runQueue();
|
void _runQueue();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@ -90,11 +90,11 @@ class AsyncEventSourceClient {
|
|||||||
|
|
||||||
AsyncClient* client() { return _client; }
|
AsyncClient* client() { return _client; }
|
||||||
void close();
|
void close();
|
||||||
void write(const char* message, size_t len);
|
bool write(const char* message, size_t len);
|
||||||
void send(const String& message, const String& event, uint32_t id = 0, uint32_t reconnect = 0) { send(message.c_str(), event.c_str(), id, reconnect); }
|
bool send(const String& message, const String& event, uint32_t id = 0, uint32_t reconnect = 0) { return send(message.c_str(), event.c_str(), id, reconnect); }
|
||||||
void send(const String& message, const char* event, uint32_t id = 0, uint32_t reconnect = 0) { send(message.c_str(), event, id, reconnect); }
|
bool send(const String& message, const char* event, uint32_t id = 0, uint32_t reconnect = 0) { return send(message.c_str(), event, id, reconnect); }
|
||||||
void send(const char* message, const char* event = NULL, uint32_t id = 0, uint32_t reconnect = 0);
|
bool send(const char* message, const char* event = NULL, uint32_t id = 0, uint32_t reconnect = 0);
|
||||||
bool connected() const { return (_client != NULL) && _client->connected(); }
|
bool connected() const { return _client && _client->connected(); }
|
||||||
uint32_t lastId() const { return _lastId; }
|
uint32_t lastId() const { return _lastId; }
|
||||||
size_t packetsWaiting() const;
|
size_t packetsWaiting() const;
|
||||||
|
|
||||||
@ -114,19 +114,28 @@ class AsyncEventSource : public AsyncWebHandler {
|
|||||||
// since simultaneous access from different tasks is possible
|
// since simultaneous access from different tasks is possible
|
||||||
mutable std::mutex _client_queue_lock;
|
mutable std::mutex _client_queue_lock;
|
||||||
#endif
|
#endif
|
||||||
ArEventHandlerFunction _connectcb{nullptr};
|
ArEventHandlerFunction _connectcb = nullptr;
|
||||||
|
ArEventHandlerFunction _disconnectcb = nullptr;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
typedef enum {
|
||||||
|
DISCARDED = 0,
|
||||||
|
ENQUEUED = 1,
|
||||||
|
PARTIALLY_ENQUEUED = 2,
|
||||||
|
} SendStatus;
|
||||||
|
|
||||||
AsyncEventSource(const String& url) : _url(url) {};
|
AsyncEventSource(const String& url) : _url(url) {};
|
||||||
~AsyncEventSource() { close(); };
|
~AsyncEventSource() { close(); };
|
||||||
|
|
||||||
const char* url() const { return _url.c_str(); }
|
const char* url() const { return _url.c_str(); }
|
||||||
void close();
|
void close();
|
||||||
void onConnect(ArEventHandlerFunction cb);
|
void onConnect(ArEventHandlerFunction cb) { _connectcb = cb; }
|
||||||
|
// The client pointer sent to the callback is only for reference purposes. DO NOT CALL ANY METHOD ON IT !
|
||||||
|
void onDisconnect(ArEventHandlerFunction cb) { _disconnectcb = cb; }
|
||||||
void authorizeConnect(ArAuthorizeConnectHandler cb);
|
void authorizeConnect(ArAuthorizeConnectHandler cb);
|
||||||
void send(const String& message, const String& event, uint32_t id = 0, uint32_t reconnect = 0) { send(message.c_str(), event.c_str(), id, reconnect); }
|
SendStatus send(const String& message, const String& event, uint32_t id = 0, uint32_t reconnect = 0) { return send(message.c_str(), event.c_str(), id, reconnect); }
|
||||||
void send(const String& message, const char* event, uint32_t id = 0, uint32_t reconnect = 0) { send(message.c_str(), event, id, reconnect); }
|
SendStatus send(const String& message, const char* event, uint32_t id = 0, uint32_t reconnect = 0) { return send(message.c_str(), event, id, reconnect); }
|
||||||
void send(const char* message, const char* event = NULL, uint32_t id = 0, uint32_t reconnect = 0);
|
SendStatus send(const char* message, const char* event = NULL, uint32_t id = 0, uint32_t reconnect = 0);
|
||||||
// number of clients connected
|
// number of clients connected
|
||||||
size_t count() const;
|
size_t count() const;
|
||||||
size_t avgPacketsWaiting() const;
|
size_t avgPacketsWaiting() const;
|
||||||
@ -134,8 +143,8 @@ class AsyncEventSource : public AsyncWebHandler {
|
|||||||
// system callbacks (do not call)
|
// system callbacks (do not call)
|
||||||
void _addClient(AsyncEventSourceClient* client);
|
void _addClient(AsyncEventSourceClient* client);
|
||||||
void _handleDisconnect(AsyncEventSourceClient* client);
|
void _handleDisconnect(AsyncEventSourceClient* client);
|
||||||
virtual bool canHandle(AsyncWebServerRequest* request) override final;
|
bool canHandle(AsyncWebServerRequest* request) const override final;
|
||||||
virtual void handleRequest(AsyncWebServerRequest* request) override final;
|
void handleRequest(AsyncWebServerRequest* request) override final;
|
||||||
};
|
};
|
||||||
|
|
||||||
class AsyncEventSourceResponse : public AsyncWebServerResponse {
|
class AsyncEventSourceResponse : public AsyncWebServerResponse {
|
||||||
|
@ -89,18 +89,14 @@ AsyncCallbackJsonWebHandler::AsyncCallbackJsonWebHandler(const String& uri, ArJs
|
|||||||
: _uri(uri), _method(HTTP_GET | HTTP_POST | HTTP_PUT | HTTP_PATCH), _onRequest(onRequest), _maxContentLength(16384) {}
|
: _uri(uri), _method(HTTP_GET | HTTP_POST | HTTP_PUT | HTTP_PATCH), _onRequest(onRequest), _maxContentLength(16384) {}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
bool AsyncCallbackJsonWebHandler::canHandle(AsyncWebServerRequest* request) {
|
bool AsyncCallbackJsonWebHandler::canHandle(AsyncWebServerRequest* request) const {
|
||||||
if (!_onRequest)
|
if (!_onRequest || !request->isHTTP() || !(_method & request->method()))
|
||||||
return false;
|
|
||||||
|
|
||||||
WebRequestMethodComposite request_method = request->method();
|
|
||||||
if (!(_method & request_method))
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (_uri.length() && (_uri != request->url() && !request->url().startsWith(_uri + "/")))
|
if (_uri.length() && (_uri != request->url() && !request->url().startsWith(_uri + "/")))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (request_method != HTTP_GET && !request->contentType().equalsIgnoreCase(asyncsrv::T_application_json))
|
if (request->method() != HTTP_GET && !request->contentType().equalsIgnoreCase(asyncsrv::T_application_json))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -119,11 +119,11 @@ class AsyncCallbackJsonWebHandler : public AsyncWebHandler {
|
|||||||
void setMaxContentLength(int maxContentLength) { _maxContentLength = maxContentLength; }
|
void setMaxContentLength(int maxContentLength) { _maxContentLength = maxContentLength; }
|
||||||
void onRequest(ArJsonRequestHandlerFunction fn) { _onRequest = fn; }
|
void onRequest(ArJsonRequestHandlerFunction fn) { _onRequest = fn; }
|
||||||
|
|
||||||
virtual bool canHandle(AsyncWebServerRequest* request) override final;
|
bool canHandle(AsyncWebServerRequest* request) const override final;
|
||||||
virtual void handleRequest(AsyncWebServerRequest* request) override final;
|
void handleRequest(AsyncWebServerRequest* request) override final;
|
||||||
virtual void handleUpload(__unused AsyncWebServerRequest* request, __unused const String& filename, __unused size_t index, __unused uint8_t* data, __unused size_t len, __unused bool final) override final {}
|
void handleUpload(__unused AsyncWebServerRequest* request, __unused const String& filename, __unused size_t index, __unused uint8_t* data, __unused size_t len, __unused bool final) override final {}
|
||||||
virtual void handleBody(AsyncWebServerRequest* request, uint8_t* data, size_t len, size_t index, size_t total) override final;
|
void handleBody(AsyncWebServerRequest* request, uint8_t* data, size_t len, size_t index, size_t total) override final;
|
||||||
virtual bool isRequestHandlerTrivial() override final { return !_onRequest; }
|
bool isRequestHandlerTrivial() const override final { return !_onRequest; }
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // ASYNC_JSON_SUPPORT == 1
|
#endif // ASYNC_JSON_SUPPORT == 1
|
||||||
|
@ -44,18 +44,14 @@ AsyncCallbackMessagePackWebHandler::AsyncCallbackMessagePackWebHandler(const Str
|
|||||||
: _uri(uri), _method(HTTP_GET | HTTP_POST | HTTP_PUT | HTTP_PATCH), _onRequest(onRequest), _maxContentLength(16384) {}
|
: _uri(uri), _method(HTTP_GET | HTTP_POST | HTTP_PUT | HTTP_PATCH), _onRequest(onRequest), _maxContentLength(16384) {}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
bool AsyncCallbackMessagePackWebHandler::canHandle(AsyncWebServerRequest* request) {
|
bool AsyncCallbackMessagePackWebHandler::canHandle(AsyncWebServerRequest* request) const {
|
||||||
if (!_onRequest)
|
if (!_onRequest || !request->isHTTP() || !(_method & request->method()))
|
||||||
return false;
|
|
||||||
|
|
||||||
WebRequestMethodComposite request_method = request->method();
|
|
||||||
if (!(_method & request_method))
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (_uri.length() && (_uri != request->url() && !request->url().startsWith(_uri + "/")))
|
if (_uri.length() && (_uri != request->url() && !request->url().startsWith(_uri + "/")))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (request_method != HTTP_GET && !request->contentType().equalsIgnoreCase(asyncsrv::T_application_msgpack))
|
if (request->method() != HTTP_GET && !request->contentType().equalsIgnoreCase(asyncsrv::T_application_msgpack))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -92,11 +92,11 @@ class AsyncCallbackMessagePackWebHandler : public AsyncWebHandler {
|
|||||||
void setMaxContentLength(int maxContentLength) { _maxContentLength = maxContentLength; }
|
void setMaxContentLength(int maxContentLength) { _maxContentLength = maxContentLength; }
|
||||||
void onRequest(ArMessagePackRequestHandlerFunction fn) { _onRequest = fn; }
|
void onRequest(ArMessagePackRequestHandlerFunction fn) { _onRequest = fn; }
|
||||||
|
|
||||||
virtual bool canHandle(AsyncWebServerRequest* request) override final;
|
bool canHandle(AsyncWebServerRequest* request) const override final;
|
||||||
virtual void handleRequest(AsyncWebServerRequest* request) override final;
|
void handleRequest(AsyncWebServerRequest* request) override final;
|
||||||
virtual void handleUpload(__unused AsyncWebServerRequest* request, __unused const String& filename, __unused size_t index, __unused uint8_t* data, __unused size_t len, __unused bool final) override final {}
|
void handleUpload(__unused AsyncWebServerRequest* request, __unused const String& filename, __unused size_t index, __unused uint8_t* data, __unused size_t len, __unused bool final) override final {}
|
||||||
virtual void handleBody(AsyncWebServerRequest* request, uint8_t* data, size_t len, size_t index, size_t total) override final;
|
void handleBody(AsyncWebServerRequest* request, uint8_t* data, size_t len, size_t index, size_t total) override final;
|
||||||
virtual bool isRequestHandlerTrivial() override final { return !_onRequest; }
|
bool isRequestHandlerTrivial() const override final { return !_onRequest; }
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // ASYNC_MSG_PACK_SUPPORT == 1
|
#endif // ASYNC_MSG_PACK_SUPPORT == 1
|
||||||
|
@ -39,7 +39,7 @@
|
|||||||
using namespace asyncsrv;
|
using namespace asyncsrv;
|
||||||
|
|
||||||
size_t webSocketSendFrameWindow(AsyncClient* client) {
|
size_t webSocketSendFrameWindow(AsyncClient* client) {
|
||||||
if (!client->canSend())
|
if (!client || !client->canSend())
|
||||||
return 0;
|
return 0;
|
||||||
size_t space = client->space();
|
size_t space = client->space();
|
||||||
if (space < 9)
|
if (space < 9)
|
||||||
@ -48,7 +48,7 @@ size_t webSocketSendFrameWindow(AsyncClient* client) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
size_t webSocketSendFrame(AsyncClient* client, bool final, uint8_t opcode, bool mask, uint8_t* data, size_t len) {
|
size_t webSocketSendFrame(AsyncClient* client, bool final, uint8_t opcode, bool mask, uint8_t* data, size_t len) {
|
||||||
if (!client->canSend()) {
|
if (!client || !client->canSend()) {
|
||||||
// Serial.println("SF 1");
|
// Serial.println("SF 1");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -185,12 +185,12 @@ class AsyncWebSocketControl {
|
|||||||
_data = NULL;
|
_data = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual ~AsyncWebSocketControl() {
|
~AsyncWebSocketControl() {
|
||||||
if (_data != NULL)
|
if (_data != NULL)
|
||||||
free(_data);
|
free(_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual bool finished() const { return _finished; }
|
bool finished() const { return _finished; }
|
||||||
uint8_t opcode() { return _opcode; }
|
uint8_t opcode() { return _opcode; }
|
||||||
uint8_t len() { return _len + 2; }
|
uint8_t len() { return _len + 2; }
|
||||||
size_t send(AsyncClient* client) {
|
size_t send(AsyncClient* client) {
|
||||||
@ -219,6 +219,9 @@ void AsyncWebSocketMessage::ack(size_t len, uint32_t time) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
size_t AsyncWebSocketMessage::send(AsyncClient* client) {
|
size_t AsyncWebSocketMessage::send(AsyncClient* client) {
|
||||||
|
if (!client)
|
||||||
|
return 0;
|
||||||
|
|
||||||
if (_status != WS_MSG_SENDING)
|
if (_status != WS_MSG_SENDING)
|
||||||
return 0;
|
return 0;
|
||||||
if (_acked < _ack) {
|
if (_acked < _ack) {
|
||||||
@ -343,7 +346,7 @@ void AsyncWebSocketClient::_onPoll() {
|
|||||||
#ifdef ESP32
|
#ifdef ESP32
|
||||||
std::unique_lock<std::mutex> lock(_lock);
|
std::unique_lock<std::mutex> lock(_lock);
|
||||||
#endif
|
#endif
|
||||||
if (_client->canSend() && (!_controlQueue.empty() || !_messageQueue.empty())) {
|
if (_client && _client->canSend() && (!_controlQueue.empty() || !_messageQueue.empty())) {
|
||||||
_runQueue();
|
_runQueue();
|
||||||
} else if (_keepAlivePeriod > 0 && (millis() - _lastMessageTime) >= _keepAlivePeriod && (_controlQueue.empty() && _messageQueue.empty())) {
|
} else if (_keepAlivePeriod > 0 && (millis() - _lastMessageTime) >= _keepAlivePeriod && (_controlQueue.empty() && _messageQueue.empty())) {
|
||||||
#ifdef ESP32
|
#ifdef ESP32
|
||||||
@ -371,16 +374,13 @@ bool AsyncWebSocketClient::queueIsFull() const {
|
|||||||
#ifdef ESP32
|
#ifdef ESP32
|
||||||
std::lock_guard<std::mutex> lock(_lock);
|
std::lock_guard<std::mutex> lock(_lock);
|
||||||
#endif
|
#endif
|
||||||
size_t size = _messageQueue.size();
|
return (_messageQueue.size() >= WS_MAX_QUEUED_MESSAGES) || (_status != WS_CONNECTED);
|
||||||
;
|
|
||||||
return (size >= WS_MAX_QUEUED_MESSAGES) || (_status != WS_CONNECTED);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t AsyncWebSocketClient::queueLen() const {
|
size_t AsyncWebSocketClient::queueLen() const {
|
||||||
#ifdef ESP32
|
#ifdef ESP32
|
||||||
std::lock_guard<std::mutex> lock(_lock);
|
std::lock_guard<std::mutex> lock(_lock);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return _messageQueue.size();
|
return _messageQueue.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -391,38 +391,43 @@ bool AsyncWebSocketClient::canSend() const {
|
|||||||
return _messageQueue.size() < WS_MAX_QUEUED_MESSAGES;
|
return _messageQueue.size() < WS_MAX_QUEUED_MESSAGES;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AsyncWebSocketClient::_queueControl(uint8_t opcode, const uint8_t* data, size_t len, bool mask) {
|
bool AsyncWebSocketClient::_queueControl(uint8_t opcode, const uint8_t* data, size_t len, bool mask) {
|
||||||
if (!_client)
|
if (!_client)
|
||||||
return;
|
return false;
|
||||||
|
|
||||||
{
|
|
||||||
#ifdef ESP32
|
#ifdef ESP32
|
||||||
std::lock_guard<std::mutex> lock(_lock);
|
std::lock_guard<std::mutex> lock(_lock);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
_controlQueue.emplace_back(opcode, data, len, mask);
|
_controlQueue.emplace_back(opcode, data, len, mask);
|
||||||
}
|
|
||||||
|
|
||||||
if (_client && _client->canSend())
|
if (_client && _client->canSend())
|
||||||
_runQueue();
|
_runQueue();
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AsyncWebSocketClient::_queueMessage(AsyncWebSocketSharedBuffer buffer, uint8_t opcode, bool mask) {
|
bool AsyncWebSocketClient::_queueMessage(AsyncWebSocketSharedBuffer buffer, uint8_t opcode, bool mask) {
|
||||||
if (!_client || buffer->size() == 0 || _status != WS_CONNECTED)
|
if (!_client || buffer->size() == 0 || _status != WS_CONNECTED)
|
||||||
return;
|
return false;
|
||||||
|
|
||||||
#ifdef ESP32
|
#ifdef ESP32
|
||||||
std::lock_guard<std::mutex> lock(_lock);
|
std::lock_guard<std::mutex> lock(_lock);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (_messageQueue.size() >= WS_MAX_QUEUED_MESSAGES) {
|
if (_messageQueue.size() >= WS_MAX_QUEUED_MESSAGES) {
|
||||||
if (closeWhenFull) {
|
if (closeWhenFull) {
|
||||||
|
_status = WS_DISCONNECTED;
|
||||||
|
|
||||||
|
if (_client)
|
||||||
|
_client->close(true);
|
||||||
|
|
||||||
#ifdef ESP8266
|
#ifdef ESP8266
|
||||||
ets_printf("AsyncWebSocketClient::_queueMessage: Too many messages queued: closing connection\n");
|
ets_printf("AsyncWebSocketClient::_queueMessage: Too many messages queued: closing connection\n");
|
||||||
#elif defined(ESP32)
|
#elif defined(ESP32)
|
||||||
log_e("Too many messages queued: closing connection");
|
log_e("Too many messages queued: closing connection");
|
||||||
#endif
|
#endif
|
||||||
_status = WS_DISCONNECTED;
|
|
||||||
if (_client)
|
|
||||||
_client->close(true);
|
|
||||||
} else {
|
} else {
|
||||||
#ifdef ESP8266
|
#ifdef ESP8266
|
||||||
ets_printf("AsyncWebSocketClient::_queueMessage: Too many messages queued: discarding new message\n");
|
ets_printf("AsyncWebSocketClient::_queueMessage: Too many messages queued: discarding new message\n");
|
||||||
@ -430,13 +435,16 @@ void AsyncWebSocketClient::_queueMessage(AsyncWebSocketSharedBuffer buffer, uint
|
|||||||
log_e("Too many messages queued: discarding new message");
|
log_e("Too many messages queued: discarding new message");
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
return;
|
|
||||||
} else {
|
return false;
|
||||||
_messageQueue.emplace_back(buffer, opcode, mask);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_messageQueue.emplace_back(buffer, opcode, mask);
|
||||||
|
|
||||||
if (_client && _client->canSend())
|
if (_client && _client->canSend())
|
||||||
_runQueue();
|
_runQueue();
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AsyncWebSocketClient::close(uint16_t code, const char* message) {
|
void AsyncWebSocketClient::close(uint16_t code, const char* message) {
|
||||||
@ -466,9 +474,8 @@ void AsyncWebSocketClient::close(uint16_t code, const char* message) {
|
|||||||
_queueControl(WS_DISCONNECT);
|
_queueControl(WS_DISCONNECT);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AsyncWebSocketClient::ping(const uint8_t* data, size_t len) {
|
bool AsyncWebSocketClient::ping(const uint8_t* data, size_t len) {
|
||||||
if (_status == WS_CONNECTED)
|
return _status == WS_CONNECTED && _queueControl(WS_PING, data, len);
|
||||||
_queueControl(WS_PING, data, len);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void AsyncWebSocketClient::_onError(int8_t) {
|
void AsyncWebSocketClient::_onError(int8_t) {
|
||||||
@ -476,6 +483,8 @@ void AsyncWebSocketClient::_onError(int8_t) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void AsyncWebSocketClient::_onTimeout(uint32_t time) {
|
void AsyncWebSocketClient::_onTimeout(uint32_t time) {
|
||||||
|
if (!_client)
|
||||||
|
return;
|
||||||
// Serial.println("onTime");
|
// Serial.println("onTime");
|
||||||
(void)time;
|
(void)time;
|
||||||
_client->close(true);
|
_client->close(true);
|
||||||
@ -483,7 +492,7 @@ void AsyncWebSocketClient::_onTimeout(uint32_t time) {
|
|||||||
|
|
||||||
void AsyncWebSocketClient::_onDisconnect() {
|
void AsyncWebSocketClient::_onDisconnect() {
|
||||||
// Serial.println("onDis");
|
// Serial.println("onDis");
|
||||||
_client = NULL;
|
_client = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AsyncWebSocketClient::_onData(void* pbuf, size_t plen) {
|
void AsyncWebSocketClient::_onData(void* pbuf, size_t plen) {
|
||||||
@ -535,7 +544,7 @@ void AsyncWebSocketClient::_onData(void* pbuf, size_t plen) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (datalen > 0)
|
if (datalen > 0)
|
||||||
_server->_handleEvent(this, WS_EVT_DATA, (void*)&_pinfo, (uint8_t*)data, datalen);
|
_server->_handleEvent(this, WS_EVT_DATA, (void*)&_pinfo, data, datalen);
|
||||||
|
|
||||||
_pinfo.index += datalen;
|
_pinfo.index += datalen;
|
||||||
} else if ((datalen + _pinfo.index) == _pinfo.len) {
|
} else if ((datalen + _pinfo.index) == _pinfo.len) {
|
||||||
@ -550,18 +559,21 @@ void AsyncWebSocketClient::_onData(void* pbuf, size_t plen) {
|
|||||||
}
|
}
|
||||||
if (_status == WS_DISCONNECTING) {
|
if (_status == WS_DISCONNECTING) {
|
||||||
_status = WS_DISCONNECTED;
|
_status = WS_DISCONNECTED;
|
||||||
|
if (_client)
|
||||||
_client->close(true);
|
_client->close(true);
|
||||||
} else {
|
} else {
|
||||||
_status = WS_DISCONNECTING;
|
_status = WS_DISCONNECTING;
|
||||||
|
if (_client)
|
||||||
_client->ackLater();
|
_client->ackLater();
|
||||||
_queueControl(WS_DISCONNECT, data, datalen);
|
_queueControl(WS_DISCONNECT, data, datalen);
|
||||||
}
|
}
|
||||||
} else if (_pinfo.opcode == WS_PING) {
|
} else if (_pinfo.opcode == WS_PING) {
|
||||||
|
_server->_handleEvent(this, WS_EVT_PING, NULL, NULL, 0);
|
||||||
_queueControl(WS_PONG, data, datalen);
|
_queueControl(WS_PONG, data, datalen);
|
||||||
} else if (_pinfo.opcode == WS_PONG) {
|
} else if (_pinfo.opcode == WS_PONG) {
|
||||||
if (datalen != AWSC_PING_PAYLOAD_LEN || memcmp(AWSC_PING_PAYLOAD, data, AWSC_PING_PAYLOAD_LEN) != 0)
|
if (datalen != AWSC_PING_PAYLOAD_LEN || memcmp(AWSC_PING_PAYLOAD, data, AWSC_PING_PAYLOAD_LEN) != 0)
|
||||||
_server->_handleEvent(this, WS_EVT_PONG, NULL, data, datalen);
|
_server->_handleEvent(this, WS_EVT_PONG, NULL, NULL, 0);
|
||||||
} else if (_pinfo.opcode < 8) { // continuation or text/binary frame
|
} else if (_pinfo.opcode < WS_DISCONNECT) { // continuation or text/binary frame
|
||||||
_server->_handleEvent(this, WS_EVT_DATA, (void*)&_pinfo, data, datalen);
|
_server->_handleEvent(this, WS_EVT_DATA, (void*)&_pinfo, data, datalen);
|
||||||
if (_pinfo.final)
|
if (_pinfo.final)
|
||||||
_pinfo.num = 0;
|
_pinfo.num = 0;
|
||||||
@ -575,7 +587,7 @@ void AsyncWebSocketClient::_onData(void* pbuf, size_t plen) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// restore byte as _handleEvent may have added a null terminator i.e., data[len] = 0;
|
// restore byte as _handleEvent may have added a null terminator i.e., data[len] = 0;
|
||||||
if (datalen > 0)
|
if (datalen)
|
||||||
data[datalen] = datalast;
|
data[datalen] = datalast;
|
||||||
|
|
||||||
data += datalen;
|
data += datalen;
|
||||||
@ -601,9 +613,9 @@ size_t AsyncWebSocketClient::printf(const char* format, ...) {
|
|||||||
len = vsnprintf(buffer, len + 1, format, arg);
|
len = vsnprintf(buffer, len + 1, format, arg);
|
||||||
va_end(arg);
|
va_end(arg);
|
||||||
|
|
||||||
text(buffer, len);
|
bool enqueued = text(buffer, len);
|
||||||
delete[] buffer;
|
delete[] buffer;
|
||||||
return len;
|
return enqueued ? len : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef ESP8266
|
#ifdef ESP8266
|
||||||
@ -625,9 +637,9 @@ size_t AsyncWebSocketClient::printf_P(PGM_P formatP, ...) {
|
|||||||
len = vsnprintf_P(buffer, len + 1, formatP, arg);
|
len = vsnprintf_P(buffer, len + 1, formatP, arg);
|
||||||
va_end(arg);
|
va_end(arg);
|
||||||
|
|
||||||
text(buffer, len);
|
bool enqueued = text(buffer, len);
|
||||||
delete[] buffer;
|
delete[] buffer;
|
||||||
return len;
|
return enqueued ? len : 0;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -639,35 +651,37 @@ namespace {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void AsyncWebSocketClient::text(AsyncWebSocketMessageBuffer* buffer) {
|
bool AsyncWebSocketClient::text(AsyncWebSocketMessageBuffer* buffer) {
|
||||||
|
bool enqueued = false;
|
||||||
if (buffer) {
|
if (buffer) {
|
||||||
text(std::move(buffer->_buffer));
|
enqueued = text(std::move(buffer->_buffer));
|
||||||
delete buffer;
|
delete buffer;
|
||||||
}
|
}
|
||||||
|
return enqueued;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AsyncWebSocketClient::text(AsyncWebSocketSharedBuffer buffer) {
|
bool AsyncWebSocketClient::text(AsyncWebSocketSharedBuffer buffer) {
|
||||||
_queueMessage(buffer);
|
return _queueMessage(buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AsyncWebSocketClient::text(const uint8_t* message, size_t len) {
|
bool AsyncWebSocketClient::text(const uint8_t* message, size_t len) {
|
||||||
text(makeSharedBuffer(message, len));
|
return text(makeSharedBuffer(message, len));
|
||||||
}
|
}
|
||||||
|
|
||||||
void AsyncWebSocketClient::text(const char* message, size_t len) {
|
bool AsyncWebSocketClient::text(const char* message, size_t len) {
|
||||||
text((const uint8_t*)message, len);
|
return text((const uint8_t*)message, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AsyncWebSocketClient::text(const char* message) {
|
bool AsyncWebSocketClient::text(const char* message) {
|
||||||
text(message, strlen(message));
|
return text(message, strlen(message));
|
||||||
}
|
}
|
||||||
|
|
||||||
void AsyncWebSocketClient::text(const String& message) {
|
bool AsyncWebSocketClient::text(const String& message) {
|
||||||
text(message.c_str(), message.length());
|
return text(message.c_str(), message.length());
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef ESP8266
|
#ifdef ESP8266
|
||||||
void AsyncWebSocketClient::text(const __FlashStringHelper* data) {
|
bool AsyncWebSocketClient::text(const __FlashStringHelper* data) {
|
||||||
PGM_P p = reinterpret_cast<PGM_P>(data);
|
PGM_P p = reinterpret_cast<PGM_P>(data);
|
||||||
|
|
||||||
size_t n = 0;
|
size_t n = 0;
|
||||||
@ -678,51 +692,57 @@ void AsyncWebSocketClient::text(const __FlashStringHelper* data) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
char* message = (char*)malloc(n + 1);
|
char* message = (char*)malloc(n + 1);
|
||||||
|
bool enqueued = false;
|
||||||
if (message) {
|
if (message) {
|
||||||
memcpy_P(message, p, n);
|
memcpy_P(message, p, n);
|
||||||
message[n] = 0;
|
message[n] = 0;
|
||||||
text(message, n);
|
enqueued = text(message, n);
|
||||||
free(message);
|
free(message);
|
||||||
}
|
}
|
||||||
|
return enqueued;
|
||||||
}
|
}
|
||||||
#endif // ESP8266
|
#endif // ESP8266
|
||||||
|
|
||||||
void AsyncWebSocketClient::binary(AsyncWebSocketMessageBuffer* buffer) {
|
bool AsyncWebSocketClient::binary(AsyncWebSocketMessageBuffer* buffer) {
|
||||||
|
bool enqueued = false;
|
||||||
if (buffer) {
|
if (buffer) {
|
||||||
binary(std::move(buffer->_buffer));
|
enqueued = binary(std::move(buffer->_buffer));
|
||||||
delete buffer;
|
delete buffer;
|
||||||
}
|
}
|
||||||
|
return enqueued;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AsyncWebSocketClient::binary(AsyncWebSocketSharedBuffer buffer) {
|
bool AsyncWebSocketClient::binary(AsyncWebSocketSharedBuffer buffer) {
|
||||||
_queueMessage(buffer, WS_BINARY);
|
return _queueMessage(buffer, WS_BINARY);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AsyncWebSocketClient::binary(const uint8_t* message, size_t len) {
|
bool AsyncWebSocketClient::binary(const uint8_t* message, size_t len) {
|
||||||
binary(makeSharedBuffer(message, len));
|
return binary(makeSharedBuffer(message, len));
|
||||||
}
|
}
|
||||||
|
|
||||||
void AsyncWebSocketClient::binary(const char* message, size_t len) {
|
bool AsyncWebSocketClient::binary(const char* message, size_t len) {
|
||||||
binary((const uint8_t*)message, len);
|
return binary((const uint8_t*)message, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AsyncWebSocketClient::binary(const char* message) {
|
bool AsyncWebSocketClient::binary(const char* message) {
|
||||||
binary(message, strlen(message));
|
return binary(message, strlen(message));
|
||||||
}
|
}
|
||||||
|
|
||||||
void AsyncWebSocketClient::binary(const String& message) {
|
bool AsyncWebSocketClient::binary(const String& message) {
|
||||||
binary(message.c_str(), message.length());
|
return binary(message.c_str(), message.length());
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef ESP8266
|
#ifdef ESP8266
|
||||||
void AsyncWebSocketClient::binary(const __FlashStringHelper* data, size_t len) {
|
bool AsyncWebSocketClient::binary(const __FlashStringHelper* data, size_t len) {
|
||||||
PGM_P p = reinterpret_cast<PGM_P>(data);
|
PGM_P p = reinterpret_cast<PGM_P>(data);
|
||||||
char* message = (char*)malloc(len);
|
char* message = (char*)malloc(len);
|
||||||
|
bool enqueued = false;
|
||||||
if (message) {
|
if (message) {
|
||||||
memcpy_P(message, p, len);
|
memcpy_P(message, p, len);
|
||||||
binary(message, len);
|
enqueued = binary(message, len);
|
||||||
free(message);
|
free(message);
|
||||||
}
|
}
|
||||||
|
return enqueued;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -801,33 +821,38 @@ void AsyncWebSocket::cleanupClients(uint16_t maxClients) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void AsyncWebSocket::ping(uint32_t id, const uint8_t* data, size_t len) {
|
bool AsyncWebSocket::ping(uint32_t id, const uint8_t* data, size_t len) {
|
||||||
if (AsyncWebSocketClient* c = client(id))
|
AsyncWebSocketClient* c = client(id);
|
||||||
c->ping(data, len);
|
return c && c->ping(data, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AsyncWebSocket::pingAll(const uint8_t* data, size_t len) {
|
AsyncWebSocket::SendStatus AsyncWebSocket::pingAll(const uint8_t* data, size_t len) {
|
||||||
|
size_t hit = 0;
|
||||||
|
size_t miss = 0;
|
||||||
for (auto& c : _clients)
|
for (auto& c : _clients)
|
||||||
if (c.status() == WS_CONNECTED)
|
if (c.status() == WS_CONNECTED && c.ping(data, len))
|
||||||
c.ping(data, len);
|
hit++;
|
||||||
|
else
|
||||||
|
miss++;
|
||||||
|
return hit == 0 ? DISCARDED : (miss == 0 ? ENQUEUED : PARTIALLY_ENQUEUED);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AsyncWebSocket::text(uint32_t id, const uint8_t* message, size_t len) {
|
bool AsyncWebSocket::text(uint32_t id, const uint8_t* message, size_t len) {
|
||||||
if (AsyncWebSocketClient* c = client(id))
|
AsyncWebSocketClient* c = client(id);
|
||||||
c->text(makeSharedBuffer(message, len));
|
return c && c->text(makeSharedBuffer(message, len));
|
||||||
}
|
}
|
||||||
void AsyncWebSocket::text(uint32_t id, const char* message, size_t len) {
|
bool AsyncWebSocket::text(uint32_t id, const char* message, size_t len) {
|
||||||
text(id, (const uint8_t*)message, len);
|
return text(id, (const uint8_t*)message, len);
|
||||||
}
|
}
|
||||||
void AsyncWebSocket::text(uint32_t id, const char* message) {
|
bool AsyncWebSocket::text(uint32_t id, const char* message) {
|
||||||
text(id, message, strlen(message));
|
return text(id, message, strlen(message));
|
||||||
}
|
}
|
||||||
void AsyncWebSocket::text(uint32_t id, const String& message) {
|
bool AsyncWebSocket::text(uint32_t id, const String& message) {
|
||||||
text(id, message.c_str(), message.length());
|
return text(id, message.c_str(), message.length());
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef ESP8266
|
#ifdef ESP8266
|
||||||
void AsyncWebSocket::text(uint32_t id, const __FlashStringHelper* data) {
|
bool AsyncWebSocket::text(uint32_t id, const __FlashStringHelper* data) {
|
||||||
PGM_P p = reinterpret_cast<PGM_P>(data);
|
PGM_P p = reinterpret_cast<PGM_P>(data);
|
||||||
|
|
||||||
size_t n = 0;
|
size_t n = 0;
|
||||||
@ -838,40 +863,44 @@ void AsyncWebSocket::text(uint32_t id, const __FlashStringHelper* data) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
char* message = (char*)malloc(n + 1);
|
char* message = (char*)malloc(n + 1);
|
||||||
|
bool enqueued = false;
|
||||||
if (message) {
|
if (message) {
|
||||||
memcpy_P(message, p, n);
|
memcpy_P(message, p, n);
|
||||||
message[n] = 0;
|
message[n] = 0;
|
||||||
text(id, message, n);
|
enqueued = text(id, message, n);
|
||||||
free(message);
|
free(message);
|
||||||
}
|
}
|
||||||
|
return enqueued;
|
||||||
}
|
}
|
||||||
#endif // ESP8266
|
#endif // ESP8266
|
||||||
|
|
||||||
void AsyncWebSocket::text(uint32_t id, AsyncWebSocketMessageBuffer* buffer) {
|
bool AsyncWebSocket::text(uint32_t id, AsyncWebSocketMessageBuffer* buffer) {
|
||||||
|
bool enqueued = false;
|
||||||
if (buffer) {
|
if (buffer) {
|
||||||
text(id, std::move(buffer->_buffer));
|
enqueued = text(id, std::move(buffer->_buffer));
|
||||||
delete buffer;
|
delete buffer;
|
||||||
}
|
}
|
||||||
|
return enqueued;
|
||||||
}
|
}
|
||||||
void AsyncWebSocket::text(uint32_t id, AsyncWebSocketSharedBuffer buffer) {
|
bool AsyncWebSocket::text(uint32_t id, AsyncWebSocketSharedBuffer buffer) {
|
||||||
if (AsyncWebSocketClient* c = client(id))
|
AsyncWebSocketClient* c = client(id);
|
||||||
c->text(buffer);
|
return c && c->text(buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AsyncWebSocket::textAll(const uint8_t* message, size_t len) {
|
AsyncWebSocket::SendStatus AsyncWebSocket::textAll(const uint8_t* message, size_t len) {
|
||||||
textAll(makeSharedBuffer(message, len));
|
return textAll(makeSharedBuffer(message, len));
|
||||||
}
|
}
|
||||||
void AsyncWebSocket::textAll(const char* message, size_t len) {
|
AsyncWebSocket::SendStatus AsyncWebSocket::textAll(const char* message, size_t len) {
|
||||||
textAll((const uint8_t*)message, len);
|
return textAll((const uint8_t*)message, len);
|
||||||
}
|
}
|
||||||
void AsyncWebSocket::textAll(const char* message) {
|
AsyncWebSocket::SendStatus AsyncWebSocket::textAll(const char* message) {
|
||||||
textAll(message, strlen(message));
|
return textAll(message, strlen(message));
|
||||||
}
|
}
|
||||||
void AsyncWebSocket::textAll(const String& message) {
|
AsyncWebSocket::SendStatus AsyncWebSocket::textAll(const String& message) {
|
||||||
textAll(message.c_str(), message.length());
|
return textAll(message.c_str(), message.length());
|
||||||
}
|
}
|
||||||
#ifdef ESP8266
|
#ifdef ESP8266
|
||||||
void AsyncWebSocket::textAll(const __FlashStringHelper* data) {
|
AsyncWebSocket::SendStatus AsyncWebSocket::textAll(const __FlashStringHelper* data) {
|
||||||
PGM_P p = reinterpret_cast<PGM_P>(data);
|
PGM_P p = reinterpret_cast<PGM_P>(data);
|
||||||
|
|
||||||
size_t n = 0;
|
size_t n = 0;
|
||||||
@ -882,99 +911,121 @@ void AsyncWebSocket::textAll(const __FlashStringHelper* data) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
char* message = (char*)malloc(n + 1);
|
char* message = (char*)malloc(n + 1);
|
||||||
|
AsyncWebSocket::SendStatus status = DISCARDED;
|
||||||
if (message) {
|
if (message) {
|
||||||
memcpy_P(message, p, n);
|
memcpy_P(message, p, n);
|
||||||
message[n] = 0;
|
message[n] = 0;
|
||||||
textAll(message, n);
|
status = textAll(message, n);
|
||||||
free(message);
|
free(message);
|
||||||
}
|
}
|
||||||
|
return status;
|
||||||
}
|
}
|
||||||
#endif // ESP8266
|
#endif // ESP8266
|
||||||
void AsyncWebSocket::textAll(AsyncWebSocketMessageBuffer* buffer) {
|
AsyncWebSocket::SendStatus AsyncWebSocket::textAll(AsyncWebSocketMessageBuffer* buffer) {
|
||||||
|
AsyncWebSocket::SendStatus status = DISCARDED;
|
||||||
if (buffer) {
|
if (buffer) {
|
||||||
textAll(std::move(buffer->_buffer));
|
status = textAll(std::move(buffer->_buffer));
|
||||||
delete buffer;
|
delete buffer;
|
||||||
}
|
}
|
||||||
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AsyncWebSocket::textAll(AsyncWebSocketSharedBuffer buffer) {
|
AsyncWebSocket::SendStatus AsyncWebSocket::textAll(AsyncWebSocketSharedBuffer buffer) {
|
||||||
|
size_t hit = 0;
|
||||||
|
size_t miss = 0;
|
||||||
for (auto& c : _clients)
|
for (auto& c : _clients)
|
||||||
if (c.status() == WS_CONNECTED)
|
if (c.status() == WS_CONNECTED && c.text(buffer))
|
||||||
c.text(buffer);
|
hit++;
|
||||||
|
else
|
||||||
|
miss++;
|
||||||
|
return hit == 0 ? DISCARDED : (miss == 0 ? ENQUEUED : PARTIALLY_ENQUEUED);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AsyncWebSocket::binary(uint32_t id, const uint8_t* message, size_t len) {
|
bool AsyncWebSocket::binary(uint32_t id, const uint8_t* message, size_t len) {
|
||||||
if (AsyncWebSocketClient* c = client(id))
|
AsyncWebSocketClient* c = client(id);
|
||||||
c->binary(makeSharedBuffer(message, len));
|
return c && c->binary(makeSharedBuffer(message, len));
|
||||||
}
|
}
|
||||||
void AsyncWebSocket::binary(uint32_t id, const char* message, size_t len) {
|
bool AsyncWebSocket::binary(uint32_t id, const char* message, size_t len) {
|
||||||
binary(id, (const uint8_t*)message, len);
|
return binary(id, (const uint8_t*)message, len);
|
||||||
}
|
}
|
||||||
void AsyncWebSocket::binary(uint32_t id, const char* message) {
|
bool AsyncWebSocket::binary(uint32_t id, const char* message) {
|
||||||
binary(id, message, strlen(message));
|
return binary(id, message, strlen(message));
|
||||||
}
|
}
|
||||||
void AsyncWebSocket::binary(uint32_t id, const String& message) {
|
bool AsyncWebSocket::binary(uint32_t id, const String& message) {
|
||||||
binary(id, message.c_str(), message.length());
|
return binary(id, message.c_str(), message.length());
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef ESP8266
|
#ifdef ESP8266
|
||||||
void AsyncWebSocket::binary(uint32_t id, const __FlashStringHelper* data, size_t len) {
|
bool AsyncWebSocket::binary(uint32_t id, const __FlashStringHelper* data, size_t len) {
|
||||||
PGM_P p = reinterpret_cast<PGM_P>(data);
|
PGM_P p = reinterpret_cast<PGM_P>(data);
|
||||||
char* message = (char*)malloc(len);
|
char* message = (char*)malloc(len);
|
||||||
|
bool enqueued = false;
|
||||||
if (message) {
|
if (message) {
|
||||||
memcpy_P(message, p, len);
|
memcpy_P(message, p, len);
|
||||||
binary(id, message, len);
|
enqueued = binary(id, message, len);
|
||||||
free(message);
|
free(message);
|
||||||
}
|
}
|
||||||
|
return enqueued;
|
||||||
}
|
}
|
||||||
#endif // ESP8266
|
#endif // ESP8266
|
||||||
|
|
||||||
void AsyncWebSocket::binary(uint32_t id, AsyncWebSocketMessageBuffer* buffer) {
|
bool AsyncWebSocket::binary(uint32_t id, AsyncWebSocketMessageBuffer* buffer) {
|
||||||
|
bool enqueued = false;
|
||||||
if (buffer) {
|
if (buffer) {
|
||||||
binary(id, std::move(buffer->_buffer));
|
enqueued = binary(id, std::move(buffer->_buffer));
|
||||||
delete buffer;
|
delete buffer;
|
||||||
}
|
}
|
||||||
|
return enqueued;
|
||||||
}
|
}
|
||||||
void AsyncWebSocket::binary(uint32_t id, AsyncWebSocketSharedBuffer buffer) {
|
bool AsyncWebSocket::binary(uint32_t id, AsyncWebSocketSharedBuffer buffer) {
|
||||||
if (AsyncWebSocketClient* c = client(id))
|
AsyncWebSocketClient* c = client(id);
|
||||||
c->binary(buffer);
|
return c && c->binary(buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AsyncWebSocket::binaryAll(const uint8_t* message, size_t len) {
|
AsyncWebSocket::SendStatus AsyncWebSocket::binaryAll(const uint8_t* message, size_t len) {
|
||||||
binaryAll(makeSharedBuffer(message, len));
|
return binaryAll(makeSharedBuffer(message, len));
|
||||||
}
|
}
|
||||||
void AsyncWebSocket::binaryAll(const char* message, size_t len) {
|
AsyncWebSocket::SendStatus AsyncWebSocket::binaryAll(const char* message, size_t len) {
|
||||||
binaryAll((const uint8_t*)message, len);
|
return binaryAll((const uint8_t*)message, len);
|
||||||
}
|
}
|
||||||
void AsyncWebSocket::binaryAll(const char* message) {
|
AsyncWebSocket::SendStatus AsyncWebSocket::binaryAll(const char* message) {
|
||||||
binaryAll(message, strlen(message));
|
return binaryAll(message, strlen(message));
|
||||||
}
|
}
|
||||||
void AsyncWebSocket::binaryAll(const String& message) {
|
AsyncWebSocket::SendStatus AsyncWebSocket::binaryAll(const String& message) {
|
||||||
binaryAll(message.c_str(), message.length());
|
return binaryAll(message.c_str(), message.length());
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef ESP8266
|
#ifdef ESP8266
|
||||||
void AsyncWebSocket::binaryAll(const __FlashStringHelper* data, size_t len) {
|
AsyncWebSocket::SendStatus AsyncWebSocket::binaryAll(const __FlashStringHelper* data, size_t len) {
|
||||||
PGM_P p = reinterpret_cast<PGM_P>(data);
|
PGM_P p = reinterpret_cast<PGM_P>(data);
|
||||||
char* message = (char*)malloc(len);
|
char* message = (char*)malloc(len);
|
||||||
|
AsyncWebSocket::SendStatus status = DISCARDED;
|
||||||
if (message) {
|
if (message) {
|
||||||
memcpy_P(message, p, len);
|
memcpy_P(message, p, len);
|
||||||
binaryAll(message, len);
|
status = binaryAll(message, len);
|
||||||
free(message);
|
free(message);
|
||||||
}
|
}
|
||||||
|
return status;
|
||||||
}
|
}
|
||||||
#endif // ESP8266
|
#endif // ESP8266
|
||||||
|
|
||||||
void AsyncWebSocket::binaryAll(AsyncWebSocketMessageBuffer* buffer) {
|
AsyncWebSocket::SendStatus AsyncWebSocket::binaryAll(AsyncWebSocketMessageBuffer* buffer) {
|
||||||
|
AsyncWebSocket::SendStatus status = DISCARDED;
|
||||||
if (buffer) {
|
if (buffer) {
|
||||||
binaryAll(std::move(buffer->_buffer));
|
status = binaryAll(std::move(buffer->_buffer));
|
||||||
delete buffer;
|
delete buffer;
|
||||||
}
|
}
|
||||||
|
return status;
|
||||||
}
|
}
|
||||||
void AsyncWebSocket::binaryAll(AsyncWebSocketSharedBuffer buffer) {
|
AsyncWebSocket::SendStatus AsyncWebSocket::binaryAll(AsyncWebSocketSharedBuffer buffer) {
|
||||||
|
size_t hit = 0;
|
||||||
|
size_t miss = 0;
|
||||||
for (auto& c : _clients)
|
for (auto& c : _clients)
|
||||||
if (c.status() == WS_CONNECTED)
|
if (c.status() == WS_CONNECTED && c.binary(buffer))
|
||||||
c.binary(buffer);
|
hit++;
|
||||||
|
else
|
||||||
|
miss++;
|
||||||
|
return hit == 0 ? DISCARDED : (miss == 0 ? ENQUEUED : PARTIALLY_ENQUEUED);
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t AsyncWebSocket::printf(uint32_t id, const char* format, ...) {
|
size_t AsyncWebSocket::printf(uint32_t id, const char* format, ...) {
|
||||||
@ -1007,9 +1058,9 @@ size_t AsyncWebSocket::printfAll(const char* format, ...) {
|
|||||||
len = vsnprintf(buffer, len + 1, format, arg);
|
len = vsnprintf(buffer, len + 1, format, arg);
|
||||||
va_end(arg);
|
va_end(arg);
|
||||||
|
|
||||||
textAll(buffer, len);
|
AsyncWebSocket::SendStatus status = textAll(buffer, len);
|
||||||
delete[] buffer;
|
delete[] buffer;
|
||||||
return len;
|
return status == DISCARDED ? 0 : len;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef ESP8266
|
#ifdef ESP8266
|
||||||
@ -1043,9 +1094,9 @@ size_t AsyncWebSocket::printfAll_P(PGM_P formatP, ...) {
|
|||||||
len = vsnprintf_P(buffer, len + 1, formatP, arg);
|
len = vsnprintf_P(buffer, len + 1, formatP, arg);
|
||||||
va_end(arg);
|
va_end(arg);
|
||||||
|
|
||||||
textAll(buffer, len);
|
AsyncWebSocket::SendStatus status = textAll(buffer, len);
|
||||||
delete[] buffer;
|
delete[] buffer;
|
||||||
return len;
|
return status == DISCARDED ? 0 : len;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -1071,14 +1122,8 @@ const char __WS_STR_UUID[] PROGMEM = {"258EAFA5-E914-47DA-95CA-C5AB0DC85B11"};
|
|||||||
#define WS_STR_ACCEPT FPSTR(__WS_STR_ACCEPT)
|
#define WS_STR_ACCEPT FPSTR(__WS_STR_ACCEPT)
|
||||||
#define WS_STR_UUID FPSTR(__WS_STR_UUID)
|
#define WS_STR_UUID FPSTR(__WS_STR_UUID)
|
||||||
|
|
||||||
bool AsyncWebSocket::canHandle(AsyncWebServerRequest* request) {
|
bool AsyncWebSocket::canHandle(AsyncWebServerRequest* request) const {
|
||||||
if (!_enabled)
|
return _enabled && request->isWebSocketUpgrade() && request->url().equals(_url);
|
||||||
return false;
|
|
||||||
|
|
||||||
if (request->method() != HTTP_GET || !request->url().equals(_url) || !request->isExpectedRequestedConnType(RCT_WS))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void AsyncWebSocket::handleRequest(AsyncWebServerRequest* request) {
|
void AsyncWebSocket::handleRequest(AsyncWebServerRequest* request) {
|
||||||
|
@ -104,6 +104,7 @@ typedef enum { WS_MSG_SENDING,
|
|||||||
WS_MSG_ERROR } AwsMessageStatus;
|
WS_MSG_ERROR } AwsMessageStatus;
|
||||||
typedef enum { WS_EVT_CONNECT,
|
typedef enum { WS_EVT_CONNECT,
|
||||||
WS_EVT_DISCONNECT,
|
WS_EVT_DISCONNECT,
|
||||||
|
WS_EVT_PING,
|
||||||
WS_EVT_PONG,
|
WS_EVT_PONG,
|
||||||
WS_EVT_ERROR,
|
WS_EVT_ERROR,
|
||||||
WS_EVT_DATA } AwsEventType;
|
WS_EVT_DATA } AwsEventType;
|
||||||
@ -164,8 +165,8 @@ class AsyncWebSocketClient {
|
|||||||
uint32_t _lastMessageTime;
|
uint32_t _lastMessageTime;
|
||||||
uint32_t _keepAlivePeriod;
|
uint32_t _keepAlivePeriod;
|
||||||
|
|
||||||
void _queueControl(uint8_t opcode, const uint8_t* data = NULL, size_t len = 0, bool mask = false);
|
bool _queueControl(uint8_t opcode, const uint8_t* data = NULL, size_t len = 0, bool mask = false);
|
||||||
void _queueMessage(AsyncWebSocketSharedBuffer buffer, uint8_t opcode = WS_TEXT, bool mask = false);
|
bool _queueMessage(AsyncWebSocketSharedBuffer buffer, uint8_t opcode = WS_TEXT, bool mask = false);
|
||||||
void _runQueue();
|
void _runQueue();
|
||||||
void _clearQueue();
|
void _clearQueue();
|
||||||
|
|
||||||
@ -212,7 +213,7 @@ class AsyncWebSocketClient {
|
|||||||
|
|
||||||
// control frames
|
// control frames
|
||||||
void close(uint16_t code = 0, const char* message = NULL);
|
void close(uint16_t code = 0, const char* message = NULL);
|
||||||
void ping(const uint8_t* data = NULL, size_t len = 0);
|
bool ping(const uint8_t* data = NULL, size_t len = 0);
|
||||||
|
|
||||||
// set auto-ping period in seconds. disabled if zero (default)
|
// set auto-ping period in seconds. disabled if zero (default)
|
||||||
void keepAlivePeriod(uint16_t seconds) {
|
void keepAlivePeriod(uint16_t seconds) {
|
||||||
@ -229,19 +230,19 @@ class AsyncWebSocketClient {
|
|||||||
|
|
||||||
size_t printf(const char* format, ...) __attribute__((format(printf, 2, 3)));
|
size_t printf(const char* format, ...) __attribute__((format(printf, 2, 3)));
|
||||||
|
|
||||||
void text(AsyncWebSocketSharedBuffer buffer);
|
bool text(AsyncWebSocketSharedBuffer buffer);
|
||||||
void text(const uint8_t* message, size_t len);
|
bool text(const uint8_t* message, size_t len);
|
||||||
void text(const char* message, size_t len);
|
bool text(const char* message, size_t len);
|
||||||
void text(const char* message);
|
bool text(const char* message);
|
||||||
void text(const String& message);
|
bool text(const String& message);
|
||||||
void text(AsyncWebSocketMessageBuffer* buffer);
|
bool text(AsyncWebSocketMessageBuffer* buffer);
|
||||||
|
|
||||||
void binary(AsyncWebSocketSharedBuffer buffer);
|
bool binary(AsyncWebSocketSharedBuffer buffer);
|
||||||
void binary(const uint8_t* message, size_t len);
|
bool binary(const uint8_t* message, size_t len);
|
||||||
void binary(const char* message, size_t len);
|
bool binary(const char* message, size_t len);
|
||||||
void binary(const char* message);
|
bool binary(const char* message);
|
||||||
void binary(const String& message);
|
bool binary(const String& message);
|
||||||
void binary(AsyncWebSocketMessageBuffer* buffer);
|
bool binary(AsyncWebSocketMessageBuffer* buffer);
|
||||||
|
|
||||||
bool canSend() const;
|
bool canSend() const;
|
||||||
|
|
||||||
@ -255,8 +256,8 @@ class AsyncWebSocketClient {
|
|||||||
|
|
||||||
#ifdef ESP8266
|
#ifdef ESP8266
|
||||||
size_t printf_P(PGM_P formatP, ...) __attribute__((format(printf, 2, 3)));
|
size_t printf_P(PGM_P formatP, ...) __attribute__((format(printf, 2, 3)));
|
||||||
void text(const __FlashStringHelper* message);
|
bool text(const __FlashStringHelper* message);
|
||||||
void binary(const __FlashStringHelper* message, size_t len);
|
bool binary(const __FlashStringHelper* message, size_t len);
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -277,6 +278,12 @@ class AsyncWebSocket : public AsyncWebHandler {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
typedef enum {
|
||||||
|
DISCARDED = 0,
|
||||||
|
ENQUEUED = 1,
|
||||||
|
PARTIALLY_ENQUEUED = 2,
|
||||||
|
} SendStatus;
|
||||||
|
|
||||||
explicit AsyncWebSocket(const char* url) : _url(url), _cNextId(1), _enabled(true) {}
|
explicit AsyncWebSocket(const char* url) : _url(url), _cNextId(1), _enabled(true) {}
|
||||||
AsyncWebSocket(const String& url) : _url(url), _cNextId(1), _enabled(true) {}
|
AsyncWebSocket(const String& url) : _url(url), _cNextId(1), _enabled(true) {}
|
||||||
~AsyncWebSocket() {};
|
~AsyncWebSocket() {};
|
||||||
@ -294,45 +301,45 @@ class AsyncWebSocket : public AsyncWebHandler {
|
|||||||
void closeAll(uint16_t code = 0, const char* message = NULL);
|
void closeAll(uint16_t code = 0, const char* message = NULL);
|
||||||
void cleanupClients(uint16_t maxClients = DEFAULT_MAX_WS_CLIENTS);
|
void cleanupClients(uint16_t maxClients = DEFAULT_MAX_WS_CLIENTS);
|
||||||
|
|
||||||
void ping(uint32_t id, const uint8_t* data = NULL, size_t len = 0);
|
bool ping(uint32_t id, const uint8_t* data = NULL, size_t len = 0);
|
||||||
void pingAll(const uint8_t* data = NULL, size_t len = 0); // done
|
SendStatus pingAll(const uint8_t* data = NULL, size_t len = 0); // done
|
||||||
|
|
||||||
void text(uint32_t id, const uint8_t* message, size_t len);
|
bool text(uint32_t id, const uint8_t* message, size_t len);
|
||||||
void text(uint32_t id, const char* message, size_t len);
|
bool text(uint32_t id, const char* message, size_t len);
|
||||||
void text(uint32_t id, const char* message);
|
bool text(uint32_t id, const char* message);
|
||||||
void text(uint32_t id, const String& message);
|
bool text(uint32_t id, const String& message);
|
||||||
void text(uint32_t id, AsyncWebSocketMessageBuffer* buffer);
|
bool text(uint32_t id, AsyncWebSocketMessageBuffer* buffer);
|
||||||
void text(uint32_t id, AsyncWebSocketSharedBuffer buffer);
|
bool text(uint32_t id, AsyncWebSocketSharedBuffer buffer);
|
||||||
|
|
||||||
void textAll(const uint8_t* message, size_t len);
|
SendStatus textAll(const uint8_t* message, size_t len);
|
||||||
void textAll(const char* message, size_t len);
|
SendStatus textAll(const char* message, size_t len);
|
||||||
void textAll(const char* message);
|
SendStatus textAll(const char* message);
|
||||||
void textAll(const String& message);
|
SendStatus textAll(const String& message);
|
||||||
void textAll(AsyncWebSocketMessageBuffer* buffer);
|
SendStatus textAll(AsyncWebSocketMessageBuffer* buffer);
|
||||||
void textAll(AsyncWebSocketSharedBuffer buffer);
|
SendStatus textAll(AsyncWebSocketSharedBuffer buffer);
|
||||||
|
|
||||||
void binary(uint32_t id, const uint8_t* message, size_t len);
|
bool binary(uint32_t id, const uint8_t* message, size_t len);
|
||||||
void binary(uint32_t id, const char* message, size_t len);
|
bool binary(uint32_t id, const char* message, size_t len);
|
||||||
void binary(uint32_t id, const char* message);
|
bool binary(uint32_t id, const char* message);
|
||||||
void binary(uint32_t id, const String& message);
|
bool binary(uint32_t id, const String& message);
|
||||||
void binary(uint32_t id, AsyncWebSocketMessageBuffer* buffer);
|
bool binary(uint32_t id, AsyncWebSocketMessageBuffer* buffer);
|
||||||
void binary(uint32_t id, AsyncWebSocketSharedBuffer buffer);
|
bool binary(uint32_t id, AsyncWebSocketSharedBuffer buffer);
|
||||||
|
|
||||||
void binaryAll(const uint8_t* message, size_t len);
|
SendStatus binaryAll(const uint8_t* message, size_t len);
|
||||||
void binaryAll(const char* message, size_t len);
|
SendStatus binaryAll(const char* message, size_t len);
|
||||||
void binaryAll(const char* message);
|
SendStatus binaryAll(const char* message);
|
||||||
void binaryAll(const String& message);
|
SendStatus binaryAll(const String& message);
|
||||||
void binaryAll(AsyncWebSocketMessageBuffer* buffer);
|
SendStatus binaryAll(AsyncWebSocketMessageBuffer* buffer);
|
||||||
void binaryAll(AsyncWebSocketSharedBuffer buffer);
|
SendStatus binaryAll(AsyncWebSocketSharedBuffer buffer);
|
||||||
|
|
||||||
size_t printf(uint32_t id, const char* format, ...) __attribute__((format(printf, 3, 4)));
|
size_t printf(uint32_t id, const char* format, ...) __attribute__((format(printf, 3, 4)));
|
||||||
size_t printfAll(const char* format, ...) __attribute__((format(printf, 2, 3)));
|
size_t printfAll(const char* format, ...) __attribute__((format(printf, 2, 3)));
|
||||||
|
|
||||||
#ifdef ESP8266
|
#ifdef ESP8266
|
||||||
void text(uint32_t id, const __FlashStringHelper* message);
|
bool text(uint32_t id, const __FlashStringHelper* message);
|
||||||
void textAll(const __FlashStringHelper* message);
|
SendStatus textAll(const __FlashStringHelper* message);
|
||||||
void binary(uint32_t id, const __FlashStringHelper* message, size_t len);
|
bool binary(uint32_t id, const __FlashStringHelper* message, size_t len);
|
||||||
void binaryAll(const __FlashStringHelper* message, size_t len);
|
SendStatus binaryAll(const __FlashStringHelper* message, size_t len);
|
||||||
size_t printf_P(uint32_t id, PGM_P formatP, ...) __attribute__((format(printf, 3, 4)));
|
size_t printf_P(uint32_t id, PGM_P formatP, ...) __attribute__((format(printf, 3, 4)));
|
||||||
size_t printfAll_P(PGM_P formatP, ...) __attribute__((format(printf, 2, 3)));
|
size_t printfAll_P(PGM_P formatP, ...) __attribute__((format(printf, 2, 3)));
|
||||||
#endif
|
#endif
|
||||||
@ -344,8 +351,8 @@ class AsyncWebSocket : public AsyncWebHandler {
|
|||||||
uint32_t _getNextId() { return _cNextId++; }
|
uint32_t _getNextId() { return _cNextId++; }
|
||||||
AsyncWebSocketClient* _newClient(AsyncWebServerRequest* request);
|
AsyncWebSocketClient* _newClient(AsyncWebServerRequest* request);
|
||||||
void _handleEvent(AsyncWebSocketClient* client, AwsEventType type, void* arg, uint8_t* data, size_t len);
|
void _handleEvent(AsyncWebSocketClient* client, AwsEventType type, void* arg, uint8_t* data, size_t len);
|
||||||
virtual bool canHandle(AsyncWebServerRequest* request) override final;
|
bool canHandle(AsyncWebServerRequest* request) const override final;
|
||||||
virtual void handleRequest(AsyncWebServerRequest* request) override final;
|
void handleRequest(AsyncWebServerRequest* request) override final;
|
||||||
|
|
||||||
// messagebuffer functions/objects.
|
// messagebuffer functions/objects.
|
||||||
AsyncWebSocketMessageBuffer* makeBuffer(size_t size = 0);
|
AsyncWebSocketMessageBuffer* makeBuffer(size_t size = 0);
|
||||||
|
@ -12,7 +12,6 @@ class ChunkPrint : public Print {
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
ChunkPrint(uint8_t* destination, size_t from, size_t len);
|
ChunkPrint(uint8_t* destination, size_t from, size_t len);
|
||||||
virtual ~ChunkPrint() {}
|
|
||||||
size_t write(uint8_t c);
|
size_t write(uint8_t c);
|
||||||
size_t write(const uint8_t* buffer, size_t size) { return this->Print::write(buffer, size); }
|
size_t write(const uint8_t* buffer, size_t size) { return this->Print::write(buffer, size); }
|
||||||
};
|
};
|
||||||
|
@ -48,10 +48,10 @@
|
|||||||
|
|
||||||
#include "literals.h"
|
#include "literals.h"
|
||||||
|
|
||||||
#define ASYNCWEBSERVER_VERSION "3.3.7"
|
#define ASYNCWEBSERVER_VERSION "3.3.23"
|
||||||
#define ASYNCWEBSERVER_VERSION_MAJOR 3
|
#define ASYNCWEBSERVER_VERSION_MAJOR 3
|
||||||
#define ASYNCWEBSERVER_VERSION_MINOR 3
|
#define ASYNCWEBSERVER_VERSION_MINOR 3
|
||||||
#define ASYNCWEBSERVER_VERSION_REVISION 7
|
#define ASYNCWEBSERVER_VERSION_REVISION 23
|
||||||
#define ASYNCWEBSERVER_FORK_mathieucarbou
|
#define ASYNCWEBSERVER_FORK_mathieucarbou
|
||||||
|
|
||||||
#ifdef ASYNCWEBSERVER_REGEX
|
#ifdef ASYNCWEBSERVER_REGEX
|
||||||
@ -140,7 +140,6 @@ class AsyncWebHeader {
|
|||||||
String _value;
|
String _value;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
AsyncWebHeader() = default;
|
|
||||||
AsyncWebHeader(const AsyncWebHeader&) = default;
|
AsyncWebHeader(const AsyncWebHeader&) = default;
|
||||||
AsyncWebHeader(const char* name, const char* value) : _name(name), _value(value) {}
|
AsyncWebHeader(const char* name, const char* value) : _name(name), _value(value) {}
|
||||||
AsyncWebHeader(const String& name, const String& value) : _name(name), _value(value) {}
|
AsyncWebHeader(const String& name, const String& value) : _name(name), _value(value) {}
|
||||||
@ -166,11 +165,12 @@ typedef enum { RCT_NOT_USED = -1,
|
|||||||
|
|
||||||
// this enum is similar to Arduino WebServer's AsyncAuthType and PsychicHttp
|
// this enum is similar to Arduino WebServer's AsyncAuthType and PsychicHttp
|
||||||
typedef enum {
|
typedef enum {
|
||||||
AUTH_NONE = 0,
|
AUTH_NONE = 0, // always allow
|
||||||
AUTH_BASIC,
|
AUTH_BASIC = 1,
|
||||||
AUTH_DIGEST,
|
AUTH_DIGEST = 2,
|
||||||
AUTH_BEARER,
|
AUTH_BEARER = 3,
|
||||||
AUTH_OTHER,
|
AUTH_OTHER = 4,
|
||||||
|
AUTH_DENIED = 255, // always returns 401
|
||||||
} AsyncAuthType;
|
} AsyncAuthType;
|
||||||
|
|
||||||
typedef std::function<size_t(uint8_t*, size_t, size_t)> AwsResponseFiller;
|
typedef std::function<size_t(uint8_t*, size_t, size_t)> AwsResponseFiller;
|
||||||
@ -264,23 +264,21 @@ class AsyncWebServerRequest {
|
|||||||
size_t contentLength() const { return _contentLength; }
|
size_t contentLength() const { return _contentLength; }
|
||||||
bool multipart() const { return _isMultipart; }
|
bool multipart() const { return _isMultipart; }
|
||||||
|
|
||||||
#ifndef ESP8266
|
|
||||||
const char* methodToString() const;
|
const char* methodToString() const;
|
||||||
const char* requestedConnTypeToString() const;
|
const char* requestedConnTypeToString() const;
|
||||||
#else
|
|
||||||
const __FlashStringHelper* methodToString() const;
|
|
||||||
const __FlashStringHelper* requestedConnTypeToString() const;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
RequestedConnectionType requestedConnType() const { return _reqconntype; }
|
RequestedConnectionType requestedConnType() const { return _reqconntype; }
|
||||||
bool isExpectedRequestedConnType(RequestedConnectionType erct1, RequestedConnectionType erct2 = RCT_NOT_USED, RequestedConnectionType erct3 = RCT_NOT_USED);
|
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); }
|
||||||
|
bool isSSE() const { return _method == HTTP_GET && isExpectedRequestedConnType(RCT_EVENT); }
|
||||||
|
bool isHTTP() const { return isExpectedRequestedConnType(RCT_DEFAULT, RCT_HTTP); }
|
||||||
void onDisconnect(ArDisconnectHandler fn);
|
void onDisconnect(ArDisconnectHandler fn);
|
||||||
|
|
||||||
// hash is the string representation of:
|
// hash is the string representation of:
|
||||||
// base64(user:pass) for basic or
|
// base64(user:pass) for basic or
|
||||||
// user:realm:md5(user:realm:pass) for digest
|
// user:realm:md5(user:realm:pass) for digest
|
||||||
bool authenticate(const char* hash);
|
bool authenticate(const char* hash) const;
|
||||||
bool authenticate(const char* username, const char* credentials, const char* realm = NULL, bool isHash = false);
|
bool authenticate(const char* username, const char* credentials, const char* realm = NULL, bool isHash = false) const;
|
||||||
void requestAuthentication(const char* realm = nullptr, bool isDigest = true) { requestAuthentication(isDigest ? AsyncAuthType::AUTH_DIGEST : AsyncAuthType::AUTH_BASIC, realm); }
|
void requestAuthentication(const char* realm = nullptr, bool isDigest = true) { requestAuthentication(isDigest ? AsyncAuthType::AUTH_DIGEST : AsyncAuthType::AUTH_BASIC, realm); }
|
||||||
void requestAuthentication(AsyncAuthType method, const char* realm = nullptr, const char* _authFailMsg = nullptr);
|
void requestAuthentication(AsyncAuthType method, const char* realm = nullptr, const char* _authFailMsg = nullptr);
|
||||||
|
|
||||||
@ -523,9 +521,7 @@ using ArMiddlewareCallback = std::function<void(AsyncWebServerRequest* request,
|
|||||||
class AsyncMiddleware {
|
class AsyncMiddleware {
|
||||||
public:
|
public:
|
||||||
virtual ~AsyncMiddleware() {}
|
virtual ~AsyncMiddleware() {}
|
||||||
virtual void run(__unused AsyncWebServerRequest* request, __unused ArMiddlewareNext next) {
|
virtual void run(__unused AsyncWebServerRequest* request, __unused ArMiddlewareNext next) { return next(); };
|
||||||
return next();
|
|
||||||
};
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend class AsyncWebHandler;
|
friend class AsyncWebHandler;
|
||||||
@ -547,7 +543,7 @@ class AsyncMiddlewareFunction : public AsyncMiddleware {
|
|||||||
// For internal use only: super class to add/remove middleware to server or handlers
|
// For internal use only: super class to add/remove middleware to server or handlers
|
||||||
class AsyncMiddlewareChain {
|
class AsyncMiddlewareChain {
|
||||||
public:
|
public:
|
||||||
virtual ~AsyncMiddlewareChain();
|
~AsyncMiddlewareChain();
|
||||||
|
|
||||||
void addMiddleware(ArMiddlewareCallback fn);
|
void addMiddleware(ArMiddlewareCallback fn);
|
||||||
void addMiddleware(AsyncMiddleware* middleware);
|
void addMiddleware(AsyncMiddleware* middleware);
|
||||||
@ -570,13 +566,26 @@ class AuthenticationMiddleware : public AsyncMiddleware {
|
|||||||
|
|
||||||
void setRealm(const char* realm) { _realm = realm; }
|
void setRealm(const char* realm) { _realm = realm; }
|
||||||
void setAuthFailureMessage(const char* message) { _authFailMsg = message; }
|
void setAuthFailureMessage(const char* message) { _authFailMsg = message; }
|
||||||
|
|
||||||
|
// set the authentication method to use
|
||||||
|
// default is AUTH_NONE: no authentication required
|
||||||
|
// AUTH_BASIC: basic authentication
|
||||||
|
// AUTH_DIGEST: digest authentication
|
||||||
|
// AUTH_BEARER: bearer token authentication
|
||||||
|
// AUTH_OTHER: other authentication method
|
||||||
|
// AUTH_DENIED: always return 401 Unauthorized
|
||||||
|
// if a method is set but no username or password is set, authentication will be ignored
|
||||||
void setAuthType(AsyncAuthType authMethod) { _authMethod = authMethod; }
|
void setAuthType(AsyncAuthType authMethod) { _authMethod = authMethod; }
|
||||||
|
|
||||||
// precompute and store the hash value based on the username, realm, and authMethod
|
// precompute and store the hash value based on the username, password, realm.
|
||||||
|
// can be used for DIGEST and BASIC to avoid recomputing the hash for each request.
|
||||||
// returns true if the hash was successfully generated and replaced
|
// returns true if the hash was successfully generated and replaced
|
||||||
bool generateHash();
|
bool generateHash();
|
||||||
|
|
||||||
bool allowed(AsyncWebServerRequest* request);
|
// returns true if the username and password (or hash) are set
|
||||||
|
bool hasCredentials() const { return _hasCreds; }
|
||||||
|
|
||||||
|
bool allowed(AsyncWebServerRequest* request) const;
|
||||||
|
|
||||||
void run(AsyncWebServerRequest* request, ArMiddlewareNext next);
|
void run(AsyncWebServerRequest* request, ArMiddlewareNext next);
|
||||||
|
|
||||||
@ -634,7 +643,7 @@ class LoggingMiddleware : public AsyncMiddleware {
|
|||||||
public:
|
public:
|
||||||
void setOutput(Print& output) { _out = &output; }
|
void setOutput(Print& output) { _out = &output; }
|
||||||
void setEnabled(bool enabled) { _enabled = enabled; }
|
void setEnabled(bool enabled) { _enabled = enabled; }
|
||||||
bool isEnabled() { return _enabled && _out; }
|
bool isEnabled() const { return _enabled && _out; }
|
||||||
|
|
||||||
void run(AsyncWebServerRequest* request, ArMiddlewareNext next);
|
void run(AsyncWebServerRequest* request, ArMiddlewareNext next);
|
||||||
|
|
||||||
@ -722,18 +731,16 @@ class AsyncWebHandler : public AsyncMiddlewareChain {
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
AsyncWebHandler() {}
|
AsyncWebHandler() {}
|
||||||
AsyncWebHandler& setFilter(ArRequestFilterFunction fn);
|
|
||||||
AsyncWebHandler& setAuthentication(const char* username, const char* password);
|
|
||||||
AsyncWebHandler& setAuthentication(const String& username, const String& password) { return setAuthentication(username.c_str(), password.c_str()); };
|
|
||||||
bool filter(AsyncWebServerRequest* request) { return _filter == NULL || _filter(request); }
|
|
||||||
virtual ~AsyncWebHandler() {}
|
virtual ~AsyncWebHandler() {}
|
||||||
virtual bool canHandle(AsyncWebServerRequest* request __attribute__((unused))) {
|
AsyncWebHandler& setFilter(ArRequestFilterFunction fn);
|
||||||
return false;
|
AsyncWebHandler& setAuthentication(const char* username, const char* password, AsyncAuthType authMethod = AsyncAuthType::AUTH_DIGEST);
|
||||||
}
|
AsyncWebHandler& setAuthentication(const String& username, const String& password, AsyncAuthType authMethod = AsyncAuthType::AUTH_DIGEST) { return setAuthentication(username.c_str(), password.c_str(), authMethod); };
|
||||||
|
bool filter(AsyncWebServerRequest* request) { return _filter == NULL || _filter(request); }
|
||||||
|
virtual bool canHandle(AsyncWebServerRequest* request __attribute__((unused))) const { return false; }
|
||||||
virtual void handleRequest(__unused AsyncWebServerRequest* request) {}
|
virtual void handleRequest(__unused AsyncWebServerRequest* request) {}
|
||||||
virtual void handleUpload(__unused AsyncWebServerRequest* request, __unused const String& filename, __unused size_t index, __unused uint8_t* data, __unused size_t len, __unused bool final) {}
|
virtual void handleUpload(__unused AsyncWebServerRequest* request, __unused const String& filename, __unused size_t index, __unused uint8_t* data, __unused size_t len, __unused bool final) {}
|
||||||
virtual void handleBody(__unused AsyncWebServerRequest* request, __unused uint8_t* data, __unused size_t len, __unused size_t index, __unused size_t total) {}
|
virtual void handleBody(__unused AsyncWebServerRequest* request, __unused uint8_t* data, __unused size_t len, __unused size_t index, __unused size_t total) {}
|
||||||
virtual bool isRequestHandlerTrivial() { return true; }
|
virtual bool isRequestHandlerTrivial() const { return true; }
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -764,26 +771,22 @@ class AsyncWebServerResponse {
|
|||||||
WebResponseState _state;
|
WebResponseState _state;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
#ifndef ESP8266
|
|
||||||
static const char* responseCodeToString(int code);
|
static const char* responseCodeToString(int code);
|
||||||
#else
|
|
||||||
static const __FlashStringHelper* responseCodeToString(int code);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
AsyncWebServerResponse();
|
AsyncWebServerResponse();
|
||||||
virtual ~AsyncWebServerResponse();
|
virtual ~AsyncWebServerResponse() {}
|
||||||
virtual void setCode(int code);
|
void setCode(int code);
|
||||||
int code() const { return _code; }
|
int code() const { return _code; }
|
||||||
virtual void setContentLength(size_t len);
|
void setContentLength(size_t len);
|
||||||
void setContentType(const String& type) { setContentType(type.c_str()); }
|
void setContentType(const String& type) { setContentType(type.c_str()); }
|
||||||
virtual void setContentType(const char* type);
|
void setContentType(const char* type);
|
||||||
virtual bool addHeader(const char* name, const char* value, bool replaceExisting = true);
|
bool addHeader(const char* name, const char* value, bool replaceExisting = true);
|
||||||
bool addHeader(const String& name, const String& value, bool replaceExisting = true) { return addHeader(name.c_str(), value.c_str(), replaceExisting); }
|
bool addHeader(const String& name, const String& value, bool replaceExisting = true) { return addHeader(name.c_str(), value.c_str(), replaceExisting); }
|
||||||
bool addHeader(const char* name, long value, bool replaceExisting = true) { return addHeader(name, String(value), replaceExisting); }
|
bool addHeader(const char* name, long value, bool replaceExisting = true) { return addHeader(name, String(value), replaceExisting); }
|
||||||
bool addHeader(const String& name, long value, bool replaceExisting = true) { return addHeader(name.c_str(), value, replaceExisting); }
|
bool addHeader(const String& name, long value, bool replaceExisting = true) { return addHeader(name.c_str(), value, replaceExisting); }
|
||||||
virtual bool removeHeader(const char* name);
|
bool removeHeader(const char* name);
|
||||||
virtual const AsyncWebHeader* getHeader(const char* name) const;
|
const AsyncWebHeader* getHeader(const char* name) const;
|
||||||
const std::list<AsyncWebHeader>& getHeaders() const { return _headers; }
|
const std::list<AsyncWebHeader>& getHeaders() const { return _headers; }
|
||||||
|
|
||||||
#ifndef ESP8266
|
#ifndef ESP8266
|
||||||
@ -794,7 +797,7 @@ class AsyncWebServerResponse {
|
|||||||
_assembleHead(buffer, version);
|
_assembleHead(buffer, version);
|
||||||
return buffer;
|
return buffer;
|
||||||
}
|
}
|
||||||
virtual void _assembleHead(String& buffer, uint8_t version);
|
void _assembleHead(String& buffer, uint8_t version);
|
||||||
|
|
||||||
virtual bool _started() const;
|
virtual bool _started() const;
|
||||||
virtual bool _finished() const;
|
virtual bool _finished() const;
|
||||||
|
@ -66,7 +66,7 @@ void AuthenticationMiddleware::setPassword(const char* password) {
|
|||||||
|
|
||||||
void AuthenticationMiddleware::setPasswordHash(const char* hash) {
|
void AuthenticationMiddleware::setPasswordHash(const char* hash) {
|
||||||
_credentials = hash;
|
_credentials = hash;
|
||||||
_hash = true;
|
_hash = _credentials.length();
|
||||||
_hasCreds = _username.length() && _credentials.length();
|
_hasCreds = _username.length() && _credentials.length();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -95,13 +95,16 @@ bool AuthenticationMiddleware::generateHash() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AuthenticationMiddleware::allowed(AsyncWebServerRequest* request) {
|
bool AuthenticationMiddleware::allowed(AsyncWebServerRequest* request) const {
|
||||||
if (_authMethod == AsyncAuthType::AUTH_NONE)
|
if (_authMethod == AsyncAuthType::AUTH_NONE)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
if (!_hasCreds)
|
if (_authMethod == AsyncAuthType::AUTH_DENIED)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
if (!_hasCreds)
|
||||||
|
return true;
|
||||||
|
|
||||||
return request->authenticate(_username.c_str(), _credentials.c_str(), _realm.c_str(), _hash);
|
return request->authenticate(_username.c_str(), _credentials.c_str(), _realm.c_str(), _hash);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -192,16 +195,16 @@ void LoggingMiddleware::run(AsyncWebServerRequest* request, ArMiddlewareNext nex
|
|||||||
}
|
}
|
||||||
|
|
||||||
void CorsMiddleware::addCORSHeaders(AsyncWebServerResponse* response) {
|
void CorsMiddleware::addCORSHeaders(AsyncWebServerResponse* response) {
|
||||||
response->addHeader(F("Access-Control-Allow-Origin"), _origin.c_str());
|
response->addHeader(asyncsrv::T_CORS_ACAO, _origin.c_str());
|
||||||
response->addHeader(F("Access-Control-Allow-Methods"), _methods.c_str());
|
response->addHeader(asyncsrv::T_CORS_ACAM, _methods.c_str());
|
||||||
response->addHeader(F("Access-Control-Allow-Headers"), _headers.c_str());
|
response->addHeader(asyncsrv::T_CORS_ACAH, _headers.c_str());
|
||||||
response->addHeader(F("Access-Control-Allow-Credentials"), _credentials ? F("true") : F("false"));
|
response->addHeader(asyncsrv::T_CORS_ACAC, _credentials ? asyncsrv::T_TRUE : asyncsrv::T_FALSE);
|
||||||
response->addHeader(F("Access-Control-Max-Age"), String(_maxAge).c_str());
|
response->addHeader(asyncsrv::T_CORS_ACMA, String(_maxAge).c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
void CorsMiddleware::run(AsyncWebServerRequest* request, ArMiddlewareNext next) {
|
void CorsMiddleware::run(AsyncWebServerRequest* request, ArMiddlewareNext next) {
|
||||||
// Origin header ? => CORS handling
|
// Origin header ? => CORS handling
|
||||||
if (request->hasHeader(F("Origin"))) {
|
if (request->hasHeader(asyncsrv::T_CORS_O)) {
|
||||||
// check if this is a preflight request => handle it and return
|
// check if this is a preflight request => handle it and return
|
||||||
if (request->method() == HTTP_OPTIONS) {
|
if (request->method() == HTTP_OPTIONS) {
|
||||||
AsyncWebServerResponse* response = request->beginResponse(200);
|
AsyncWebServerResponse* response = request->beginResponse(200);
|
||||||
@ -247,7 +250,7 @@ void RateLimitMiddleware::run(AsyncWebServerRequest* request, ArMiddlewareNext n
|
|||||||
next();
|
next();
|
||||||
} else {
|
} else {
|
||||||
AsyncWebServerResponse* response = request->beginResponse(429);
|
AsyncWebServerResponse* response = request->beginResponse(429);
|
||||||
response->addHeader(F("Retry-After"), retryAfterSeconds);
|
response->addHeader(asyncsrv::T_retry_after, retryAfterSeconds);
|
||||||
request->send(response);
|
request->send(response);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -137,11 +137,7 @@ String generateDigestHash(const char* username, const char* password, const char
|
|||||||
return in;
|
return in;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef ESP8266
|
|
||||||
bool checkDigestAuthentication(const char* header, const char* method, const char* username, const char* password, const char* realm, bool passwordIsHash, const char* nonce, const char* opaque, const char* uri)
|
bool checkDigestAuthentication(const char* header, const char* method, const char* username, const char* password, const char* realm, bool passwordIsHash, const char* nonce, const char* opaque, const char* uri)
|
||||||
#else
|
|
||||||
bool checkDigestAuthentication(const char* header, const __FlashStringHelper* method, const char* username, const char* password, const char* realm, bool passwordIsHash, const char* nonce, const char* opaque, const char* uri)
|
|
||||||
#endif
|
|
||||||
{
|
{
|
||||||
if (username == NULL || password == NULL || header == NULL || method == NULL) {
|
if (username == NULL || password == NULL || header == NULL || method == NULL) {
|
||||||
// os_printf("AUTH FAIL: missing requred fields\n");
|
// os_printf("AUTH FAIL: missing requred fields\n");
|
||||||
|
@ -28,10 +28,6 @@ bool checkBasicAuthentication(const char* header, const char* username, const ch
|
|||||||
|
|
||||||
bool checkDigestAuthentication(const char* header, const char* method, const char* username, const char* password, const char* realm, bool passwordIsHash, const char* nonce, const char* opaque, const char* uri);
|
bool checkDigestAuthentication(const char* header, const char* method, const char* username, const char* password, const char* realm, bool passwordIsHash, const char* nonce, const char* opaque, const char* uri);
|
||||||
|
|
||||||
#ifdef ESP8266
|
|
||||||
bool checkDigestAuthentication(const char* header, const __FlashStringHelper* method, const char* username, const char* password, const char* realm, bool passwordIsHash, const char* nonce, const char* opaque, const char* uri);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// for storing hashed versions on the device that can be authenticated against
|
// for storing hashed versions on the device that can be authenticated against
|
||||||
String generateDigestHash(const char* username, const char* password, const char* realm);
|
String generateDigestHash(const char* username, const char* password, const char* realm);
|
||||||
|
|
||||||
|
@ -34,8 +34,8 @@ class AsyncStaticWebHandler : public AsyncWebHandler {
|
|||||||
using FS = fs::FS;
|
using FS = fs::FS;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool _getFile(AsyncWebServerRequest* request);
|
bool _getFile(AsyncWebServerRequest* request) const;
|
||||||
bool _fileExists(AsyncWebServerRequest* request, const String& path);
|
bool _searchFile(AsyncWebServerRequest* request, const String& path);
|
||||||
uint8_t _countBits(const uint8_t value) const;
|
uint8_t _countBits(const uint8_t value) const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
@ -47,13 +47,13 @@ class AsyncStaticWebHandler : public AsyncWebHandler {
|
|||||||
String _last_modified;
|
String _last_modified;
|
||||||
AwsTemplateProcessor _callback;
|
AwsTemplateProcessor _callback;
|
||||||
bool _isDir;
|
bool _isDir;
|
||||||
bool _gzipFirst;
|
bool _tryGzipFirst = true;
|
||||||
uint8_t _gzipStats;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
AsyncStaticWebHandler(const char* uri, FS& fs, const char* path, const char* cache_control);
|
AsyncStaticWebHandler(const char* uri, FS& fs, const char* path, const char* cache_control);
|
||||||
virtual bool canHandle(AsyncWebServerRequest* request) override final;
|
bool canHandle(AsyncWebServerRequest* request) const override final;
|
||||||
virtual void handleRequest(AsyncWebServerRequest* request) override final;
|
void handleRequest(AsyncWebServerRequest* request) override final;
|
||||||
|
AsyncStaticWebHandler& setTryGzipFirst(bool value);
|
||||||
AsyncStaticWebHandler& setIsDir(bool isDir);
|
AsyncStaticWebHandler& setIsDir(bool isDir);
|
||||||
AsyncStaticWebHandler& setDefaultFile(const char* filename);
|
AsyncStaticWebHandler& setDefaultFile(const char* filename);
|
||||||
AsyncStaticWebHandler& setCacheControl(const char* cache_control);
|
AsyncStaticWebHandler& setCacheControl(const char* cache_control);
|
||||||
@ -84,11 +84,11 @@ class AsyncCallbackWebHandler : public AsyncWebHandler {
|
|||||||
void onUpload(ArUploadHandlerFunction fn) { _onUpload = fn; }
|
void onUpload(ArUploadHandlerFunction fn) { _onUpload = fn; }
|
||||||
void onBody(ArBodyHandlerFunction fn) { _onBody = fn; }
|
void onBody(ArBodyHandlerFunction fn) { _onBody = fn; }
|
||||||
|
|
||||||
virtual bool canHandle(AsyncWebServerRequest* request) override final;
|
bool canHandle(AsyncWebServerRequest* request) const override final;
|
||||||
virtual void handleRequest(AsyncWebServerRequest* request) override final;
|
void handleRequest(AsyncWebServerRequest* request) override final;
|
||||||
virtual void handleUpload(AsyncWebServerRequest* request, const String& filename, size_t index, uint8_t* data, size_t len, bool final) override final;
|
void handleUpload(AsyncWebServerRequest* request, const String& filename, size_t index, uint8_t* data, size_t len, bool final) override final;
|
||||||
virtual void handleBody(AsyncWebServerRequest* request, uint8_t* data, size_t len, size_t index, size_t total) override final;
|
void handleBody(AsyncWebServerRequest* request, uint8_t* data, size_t len, size_t index, size_t total) override final;
|
||||||
virtual bool isRequestHandlerTrivial() override final { return !_onRequest; }
|
bool isRequestHandlerTrivial() const override final { return !_onRequest; }
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* ASYNCWEBSERVERHANDLERIMPL_H_ */
|
#endif /* ASYNCWEBSERVERHANDLERIMPL_H_ */
|
||||||
|
@ -27,7 +27,7 @@ AsyncWebHandler& AsyncWebHandler::setFilter(ArRequestFilterFunction fn) {
|
|||||||
_filter = fn;
|
_filter = fn;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
AsyncWebHandler& AsyncWebHandler::setAuthentication(const char* username, const char* password) {
|
AsyncWebHandler& AsyncWebHandler::setAuthentication(const char* username, const char* password, AsyncAuthType authMethod) {
|
||||||
if (!_authMiddleware) {
|
if (!_authMiddleware) {
|
||||||
_authMiddleware = new AuthenticationMiddleware();
|
_authMiddleware = new AuthenticationMiddleware();
|
||||||
_authMiddleware->_freeOnRemoval = true;
|
_authMiddleware->_freeOnRemoval = true;
|
||||||
@ -35,6 +35,7 @@ AsyncWebHandler& AsyncWebHandler::setAuthentication(const char* username, const
|
|||||||
}
|
}
|
||||||
_authMiddleware->setUsername(username);
|
_authMiddleware->setUsername(username);
|
||||||
_authMiddleware->setPassword(password);
|
_authMiddleware->setPassword(password);
|
||||||
|
_authMiddleware->setAuthType(authMethod);
|
||||||
return *this;
|
return *this;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -56,10 +57,11 @@ AsyncStaticWebHandler::AsyncStaticWebHandler(const char* uri, FS& fs, const char
|
|||||||
_uri = _uri.substring(0, _uri.length() - 1);
|
_uri = _uri.substring(0, _uri.length() - 1);
|
||||||
if (_path[_path.length() - 1] == '/')
|
if (_path[_path.length() - 1] == '/')
|
||||||
_path = _path.substring(0, _path.length() - 1);
|
_path = _path.substring(0, _path.length() - 1);
|
||||||
|
}
|
||||||
|
|
||||||
// Reset stats
|
AsyncStaticWebHandler& AsyncStaticWebHandler::setTryGzipFirst(bool value) {
|
||||||
_gzipFirst = false;
|
_tryGzipFirst = value;
|
||||||
_gzipStats = 0xF8;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
AsyncStaticWebHandler& AsyncStaticWebHandler::setIsDir(bool isDir) {
|
AsyncStaticWebHandler& AsyncStaticWebHandler::setIsDir(bool isDir) {
|
||||||
@ -104,14 +106,11 @@ AsyncStaticWebHandler& AsyncStaticWebHandler::setLastModified() {
|
|||||||
return setLastModified(last_modified);
|
return setLastModified(last_modified);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
bool AsyncStaticWebHandler::canHandle(AsyncWebServerRequest* request) {
|
bool AsyncStaticWebHandler::canHandle(AsyncWebServerRequest* request) const {
|
||||||
if (request->method() != HTTP_GET || !request->url().startsWith(_uri) || !request->isExpectedRequestedConnType(RCT_DEFAULT, RCT_HTTP)) {
|
return request->isHTTP() && request->method() == HTTP_GET && request->url().startsWith(_uri) && _getFile(request);
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return _getFile(request);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AsyncStaticWebHandler::_getFile(AsyncWebServerRequest* request) {
|
bool AsyncStaticWebHandler::_getFile(AsyncWebServerRequest* request) const {
|
||||||
// Remove the found uri
|
// Remove the found uri
|
||||||
String path = request->url().substring(_uri.length());
|
String path = request->url().substring(_uri.length());
|
||||||
|
|
||||||
@ -121,7 +120,7 @@ bool AsyncStaticWebHandler::_getFile(AsyncWebServerRequest* request) {
|
|||||||
path = _path + path;
|
path = _path + path;
|
||||||
|
|
||||||
// Do we have a file or .gz file
|
// Do we have a file or .gz file
|
||||||
if (!canSkipFileCheck && _fileExists(request, path))
|
if (!canSkipFileCheck && const_cast<AsyncStaticWebHandler*>(this)->_searchFile(request, path))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
// Can't handle if not default file
|
// Can't handle if not default file
|
||||||
@ -133,7 +132,7 @@ bool AsyncStaticWebHandler::_getFile(AsyncWebServerRequest* request) {
|
|||||||
path += String('/');
|
path += String('/');
|
||||||
path += _default_file;
|
path += _default_file;
|
||||||
|
|
||||||
return _fileExists(request, path);
|
return const_cast<AsyncStaticWebHandler*>(this)->_searchFile(request, path);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef ESP32
|
#ifdef ESP32
|
||||||
@ -142,13 +141,13 @@ bool AsyncStaticWebHandler::_getFile(AsyncWebServerRequest* request) {
|
|||||||
#define FILE_IS_REAL(f) (f == true)
|
#define FILE_IS_REAL(f) (f == true)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
bool AsyncStaticWebHandler::_fileExists(AsyncWebServerRequest* request, const String& path) {
|
bool AsyncStaticWebHandler::_searchFile(AsyncWebServerRequest* request, const String& path) {
|
||||||
bool fileFound = false;
|
bool fileFound = false;
|
||||||
bool gzipFound = false;
|
bool gzipFound = false;
|
||||||
|
|
||||||
String gzip = path + F(".gz");
|
String gzip = path + T__gz;
|
||||||
|
|
||||||
if (_gzipFirst) {
|
if (_tryGzipFirst) {
|
||||||
if (_fs.exists(gzip)) {
|
if (_fs.exists(gzip)) {
|
||||||
request->_tempFile = _fs.open(gzip, fs::FileOpenMode::read);
|
request->_tempFile = _fs.open(gzip, fs::FileOpenMode::read);
|
||||||
gzipFound = FILE_IS_REAL(request->_tempFile);
|
gzipFound = FILE_IS_REAL(request->_tempFile);
|
||||||
@ -180,15 +179,6 @@ bool AsyncStaticWebHandler::_fileExists(AsyncWebServerRequest* request, const St
|
|||||||
char* _tempPath = (char*)malloc(pathLen + 1);
|
char* _tempPath = (char*)malloc(pathLen + 1);
|
||||||
snprintf_P(_tempPath, pathLen + 1, PSTR("%s"), path.c_str());
|
snprintf_P(_tempPath, pathLen + 1, PSTR("%s"), path.c_str());
|
||||||
request->_tempObject = (void*)_tempPath;
|
request->_tempObject = (void*)_tempPath;
|
||||||
|
|
||||||
// Calculate gzip statistic
|
|
||||||
_gzipStats = (_gzipStats << 1) + (gzipFound ? 1 : 0);
|
|
||||||
if (_gzipStats == 0x00)
|
|
||||||
_gzipFirst = false; // All files are not gzip
|
|
||||||
else if (_gzipStats == 0xFF)
|
|
||||||
_gzipFirst = true; // All files are gzip
|
|
||||||
else
|
|
||||||
_gzipFirst = _countBits(_gzipStats) > 4; // IF we have more gzip files - try gzip first
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return found;
|
return found;
|
||||||
@ -260,11 +250,8 @@ void AsyncCallbackWebHandler::setUri(const String& uri) {
|
|||||||
_isRegex = uri.startsWith("^") && uri.endsWith("$");
|
_isRegex = uri.startsWith("^") && uri.endsWith("$");
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AsyncCallbackWebHandler::canHandle(AsyncWebServerRequest* request) {
|
bool AsyncCallbackWebHandler::canHandle(AsyncWebServerRequest* request) const {
|
||||||
if (!_onRequest)
|
if (!_onRequest || !request->isHTTP() || !(_method & request->method()))
|
||||||
return false;
|
|
||||||
|
|
||||||
if (!(_method & request->method()))
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
#ifdef ASYNCWEBSERVER_REGEX
|
#ifdef ASYNCWEBSERVER_REGEX
|
||||||
|
@ -49,9 +49,9 @@ AsyncWebServerRequest::~AsyncWebServerRequest() {
|
|||||||
|
|
||||||
_pathParams.clear();
|
_pathParams.clear();
|
||||||
|
|
||||||
if (_response != NULL) {
|
AsyncWebServerResponse* r = _response;
|
||||||
delete _response;
|
_response = NULL;
|
||||||
}
|
delete r;
|
||||||
|
|
||||||
if (_tempObject != NULL) {
|
if (_tempObject != NULL) {
|
||||||
free(_tempObject);
|
free(_tempObject);
|
||||||
@ -280,24 +280,27 @@ bool AsyncWebServerRequest::_parseReqHeader() {
|
|||||||
}
|
}
|
||||||
} else if (name.equalsIgnoreCase(T_Content_Length)) {
|
} else if (name.equalsIgnoreCase(T_Content_Length)) {
|
||||||
_contentLength = atoi(value.c_str());
|
_contentLength = atoi(value.c_str());
|
||||||
} else if (name.equalsIgnoreCase(T_EXPECT) && value == T_100_CONTINUE) {
|
} else if (name.equalsIgnoreCase(T_EXPECT) && value.equalsIgnoreCase(T_100_CONTINUE)) {
|
||||||
_expectingContinue = true;
|
_expectingContinue = true;
|
||||||
} else if (name.equalsIgnoreCase(T_AUTH)) {
|
} else if (name.equalsIgnoreCase(T_AUTH)) {
|
||||||
if (value.length() > 5 && value.substring(0, 5).equalsIgnoreCase(T_BASIC)) {
|
int space = value.indexOf(' ');
|
||||||
_authorization = value.substring(6);
|
if (space == -1) {
|
||||||
_authMethod = AsyncAuthType::AUTH_BASIC;
|
|
||||||
} else if (value.length() > 6 && value.substring(0, 6).equalsIgnoreCase(T_DIGEST)) {
|
|
||||||
_authMethod = AsyncAuthType::AUTH_DIGEST;
|
|
||||||
_authorization = value.substring(7);
|
|
||||||
} else if (value.length() > 6 && value.substring(0, 6).equalsIgnoreCase(T_BEARER)) {
|
|
||||||
_authMethod = AsyncAuthType::AUTH_BEARER;
|
|
||||||
_authorization = value.substring(7);
|
|
||||||
} else {
|
|
||||||
_authorization = value;
|
_authorization = value;
|
||||||
_authMethod = AsyncAuthType::AUTH_OTHER;
|
_authMethod = AsyncAuthType::AUTH_OTHER;
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
if (name.equalsIgnoreCase(T_UPGRADE) && value.equalsIgnoreCase(T_WS)) {
|
String method = value.substring(0, space);
|
||||||
|
if (method.equalsIgnoreCase(T_BASIC)) {
|
||||||
|
_authMethod = AsyncAuthType::AUTH_BASIC;
|
||||||
|
} else if (method.equalsIgnoreCase(T_DIGEST)) {
|
||||||
|
_authMethod = AsyncAuthType::AUTH_DIGEST;
|
||||||
|
} else if (method.equalsIgnoreCase(T_BEARER)) {
|
||||||
|
_authMethod = AsyncAuthType::AUTH_BEARER;
|
||||||
|
} else {
|
||||||
|
_authMethod = AsyncAuthType::AUTH_OTHER;
|
||||||
|
}
|
||||||
|
_authorization = value.substring(space + 1);
|
||||||
|
}
|
||||||
|
} else if (name.equalsIgnoreCase(T_UPGRADE) && value.equalsIgnoreCase(T_WS)) {
|
||||||
// WebSocket request can be uniquely identified by header: [Upgrade: websocket]
|
// WebSocket request can be uniquely identified by header: [Upgrade: websocket]
|
||||||
_reqconntype = RCT_WS;
|
_reqconntype = RCT_WS;
|
||||||
} else if (name.equalsIgnoreCase(T_ACCEPT)) {
|
} else if (name.equalsIgnoreCase(T_ACCEPT)) {
|
||||||
@ -313,7 +316,6 @@ bool AsyncWebServerRequest::_parseReqHeader() {
|
|||||||
_reqconntype = RCT_EVENT;
|
_reqconntype = RCT_EVENT;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
_headers.emplace_back(name, value);
|
_headers.emplace_back(name, value);
|
||||||
}
|
}
|
||||||
#ifndef TARGET_RP2040
|
#ifndef TARGET_RP2040
|
||||||
@ -779,7 +781,7 @@ void AsyncWebServerRequest::redirect(const char* url, int code) {
|
|||||||
send(response);
|
send(response);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AsyncWebServerRequest::authenticate(const char* username, const char* password, const char* realm, bool passwordIsHash) {
|
bool AsyncWebServerRequest::authenticate(const char* username, const char* password, const char* realm, bool passwordIsHash) const {
|
||||||
if (_authorization.length()) {
|
if (_authorization.length()) {
|
||||||
if (_authMethod == AsyncAuthType::AUTH_DIGEST)
|
if (_authMethod == AsyncAuthType::AUTH_DIGEST)
|
||||||
return checkDigestAuthentication(_authorization.c_str(), methodToString(), username, password, realm, passwordIsHash, NULL, NULL, NULL);
|
return checkDigestAuthentication(_authorization.c_str(), methodToString(), username, password, realm, passwordIsHash, NULL, NULL, NULL);
|
||||||
@ -791,7 +793,7 @@ bool AsyncWebServerRequest::authenticate(const char* username, const char* passw
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AsyncWebServerRequest::authenticate(const char* hash) {
|
bool AsyncWebServerRequest::authenticate(const char* hash) const {
|
||||||
if (!_authorization.length() || hash == NULL)
|
if (!_authorization.length() || hash == NULL)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
@ -831,7 +833,7 @@ void AsyncWebServerRequest::requestAuthentication(AsyncAuthType method, const ch
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case AsyncAuthType::AUTH_DIGEST: {
|
case AsyncAuthType::AUTH_DIGEST: {
|
||||||
constexpr size_t len = strlen(T_DIGEST_) + strlen(T_realm__) + strlen(T_auth_nonce) + 32 + strlen(T__opaque) + 32 + 1;
|
size_t len = strlen(T_DIGEST_) + strlen(T_realm__) + strlen(T_auth_nonce) + 32 + strlen(T__opaque) + 32 + 1;
|
||||||
String header;
|
String header;
|
||||||
header.reserve(len + strlen(realm));
|
header.reserve(len + strlen(realm));
|
||||||
header.concat(T_DIGEST_);
|
header.concat(T_DIGEST_);
|
||||||
@ -938,7 +940,6 @@ String AsyncWebServerRequest::urlDecode(const String& text) const {
|
|||||||
return decoded;
|
return decoded;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef ESP8266
|
|
||||||
const char* AsyncWebServerRequest::methodToString() const {
|
const char* AsyncWebServerRequest::methodToString() const {
|
||||||
if (_method == HTTP_ANY)
|
if (_method == HTTP_ANY)
|
||||||
return T_ANY;
|
return T_ANY;
|
||||||
@ -958,29 +959,7 @@ const char* AsyncWebServerRequest::methodToString() const {
|
|||||||
return T_OPTIONS;
|
return T_OPTIONS;
|
||||||
return T_UNKNOWN;
|
return T_UNKNOWN;
|
||||||
}
|
}
|
||||||
#else // ESP8266
|
|
||||||
const __FlashStringHelper* AsyncWebServerRequest::methodToString() const {
|
|
||||||
if (_method == HTTP_ANY)
|
|
||||||
return FPSTR(T_ANY);
|
|
||||||
if (_method & HTTP_GET)
|
|
||||||
return FPSTR(T_GET);
|
|
||||||
if (_method & HTTP_POST)
|
|
||||||
return FPSTR(T_POST);
|
|
||||||
if (_method & HTTP_DELETE)
|
|
||||||
return FPSTR(T_DELETE);
|
|
||||||
if (_method & HTTP_PUT)
|
|
||||||
return FPSTR(T_PUT);
|
|
||||||
if (_method & HTTP_PATCH)
|
|
||||||
return FPSTR(T_PATCH);
|
|
||||||
if (_method & HTTP_HEAD)
|
|
||||||
return FPSTR(T_HEAD);
|
|
||||||
if (_method & HTTP_OPTIONS)
|
|
||||||
return FPSTR(T_OPTIONS);
|
|
||||||
return FPSTR(T_UNKNOWN);
|
|
||||||
}
|
|
||||||
#endif // ESP8266
|
|
||||||
|
|
||||||
#ifndef ESP8266
|
|
||||||
const char* AsyncWebServerRequest::requestedConnTypeToString() const {
|
const char* AsyncWebServerRequest::requestedConnTypeToString() const {
|
||||||
switch (_reqconntype) {
|
switch (_reqconntype) {
|
||||||
case RCT_NOT_USED:
|
case RCT_NOT_USED:
|
||||||
@ -997,32 +976,9 @@ const char* AsyncWebServerRequest::requestedConnTypeToString() const {
|
|||||||
return T_ERROR;
|
return T_ERROR;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#else // ESP8266
|
|
||||||
const __FlashStringHelper* AsyncWebServerRequest::requestedConnTypeToString() const {
|
|
||||||
switch (_reqconntype) {
|
|
||||||
case RCT_NOT_USED:
|
|
||||||
return FPSTR(T_RCT_NOT_USED);
|
|
||||||
case RCT_DEFAULT:
|
|
||||||
return FPSTR(T_RCT_DEFAULT);
|
|
||||||
case RCT_HTTP:
|
|
||||||
return FPSTR(T_RCT_HTTP);
|
|
||||||
case RCT_WS:
|
|
||||||
return FPSTR(T_RCT_WS);
|
|
||||||
case RCT_EVENT:
|
|
||||||
return FPSTR(T_RCT_EVENT);
|
|
||||||
default:
|
|
||||||
return FPSTR(T_ERROR);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif // ESP8266
|
|
||||||
|
|
||||||
bool AsyncWebServerRequest::isExpectedRequestedConnType(RequestedConnectionType erct1, RequestedConnectionType erct2, RequestedConnectionType erct3) {
|
bool AsyncWebServerRequest::isExpectedRequestedConnType(RequestedConnectionType erct1, RequestedConnectionType erct2, RequestedConnectionType erct3) const {
|
||||||
bool res = false;
|
return ((erct1 != RCT_NOT_USED) && (erct1 == _reqconntype)) ||
|
||||||
if ((erct1 != RCT_NOT_USED) && (erct1 == _reqconntype))
|
((erct2 != RCT_NOT_USED) && (erct2 == _reqconntype)) ||
|
||||||
res = true;
|
((erct3 != RCT_NOT_USED) && (erct3 == _reqconntype));
|
||||||
if ((erct2 != RCT_NOT_USED) && (erct2 == _reqconntype))
|
|
||||||
res = true;
|
|
||||||
if ((erct3 != RCT_NOT_USED) && (erct3 == _reqconntype))
|
|
||||||
res = true;
|
|
||||||
return res;
|
|
||||||
}
|
}
|
||||||
|
@ -26,9 +26,10 @@
|
|||||||
#undef min
|
#undef min
|
||||||
#undef max
|
#undef max
|
||||||
#endif
|
#endif
|
||||||
|
#include "literals.h"
|
||||||
|
#include <StreamString.h>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include "literals.h"
|
|
||||||
|
|
||||||
// It is possible to restore these defines, but one can use _min and _max instead. Or std::min, std::max.
|
// It is possible to restore these defines, but one can use _min and _max instead. Or std::min, std::max.
|
||||||
|
|
||||||
@ -39,9 +40,9 @@ class AsyncBasicResponse : public AsyncWebServerResponse {
|
|||||||
public:
|
public:
|
||||||
explicit AsyncBasicResponse(int code, const char* contentType = asyncsrv::empty, const char* content = asyncsrv::empty);
|
explicit AsyncBasicResponse(int code, const char* contentType = asyncsrv::empty, const char* content = asyncsrv::empty);
|
||||||
AsyncBasicResponse(int code, const String& contentType, const String& content = emptyString) : AsyncBasicResponse(code, contentType.c_str(), content.c_str()) {}
|
AsyncBasicResponse(int code, const String& contentType, const String& content = emptyString) : AsyncBasicResponse(code, contentType.c_str(), content.c_str()) {}
|
||||||
void _respond(AsyncWebServerRequest* request);
|
void _respond(AsyncWebServerRequest* request) override final;
|
||||||
size_t _ack(AsyncWebServerRequest* request, size_t len, uint32_t time);
|
size_t _ack(AsyncWebServerRequest* request, size_t len, uint32_t time) override final;
|
||||||
bool _sourceValid() const { return true; }
|
bool _sourceValid() const override final { return true; }
|
||||||
};
|
};
|
||||||
|
|
||||||
class AsyncAbstractResponse : public AsyncWebServerResponse {
|
class AsyncAbstractResponse : public AsyncWebServerResponse {
|
||||||
@ -60,9 +61,10 @@ class AsyncAbstractResponse : public AsyncWebServerResponse {
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
AsyncAbstractResponse(AwsTemplateProcessor callback = nullptr);
|
AsyncAbstractResponse(AwsTemplateProcessor callback = nullptr);
|
||||||
void _respond(AsyncWebServerRequest* request);
|
virtual ~AsyncAbstractResponse() {}
|
||||||
size_t _ack(AsyncWebServerRequest* request, size_t len, uint32_t time);
|
void _respond(AsyncWebServerRequest* request) override final;
|
||||||
bool _sourceValid() const { return false; }
|
size_t _ack(AsyncWebServerRequest* request, size_t len, uint32_t time) override final;
|
||||||
|
virtual bool _sourceValid() const { return false; }
|
||||||
virtual size_t _fillBuffer(uint8_t* buf __attribute__((unused)), size_t maxLen __attribute__((unused))) { return 0; }
|
virtual size_t _fillBuffer(uint8_t* buf __attribute__((unused)), size_t maxLen __attribute__((unused))) { return 0; }
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -85,9 +87,9 @@ class AsyncFileResponse : public AsyncAbstractResponse {
|
|||||||
AsyncFileResponse(FS& fs, const String& path, const String& contentType, bool download = false, AwsTemplateProcessor callback = nullptr) : AsyncFileResponse(fs, path, contentType.c_str(), download, callback) {}
|
AsyncFileResponse(FS& fs, const String& path, const String& contentType, bool download = false, AwsTemplateProcessor callback = nullptr) : AsyncFileResponse(fs, path, contentType.c_str(), download, callback) {}
|
||||||
AsyncFileResponse(File content, const String& path, const char* contentType = asyncsrv::empty, bool download = false, AwsTemplateProcessor callback = nullptr);
|
AsyncFileResponse(File content, const String& path, const char* contentType = asyncsrv::empty, bool download = false, AwsTemplateProcessor callback = nullptr);
|
||||||
AsyncFileResponse(File content, const String& path, const String& contentType, bool download = false, AwsTemplateProcessor callack = nullptr) : AsyncFileResponse(content, path, contentType.c_str(), download, callack) {}
|
AsyncFileResponse(File content, const String& path, const String& contentType, bool download = false, AwsTemplateProcessor callack = nullptr) : AsyncFileResponse(content, path, contentType.c_str(), download, callack) {}
|
||||||
~AsyncFileResponse();
|
~AsyncFileResponse() { _content.close(); }
|
||||||
bool _sourceValid() const { return !!(_content); }
|
bool _sourceValid() const override final { return !!(_content); }
|
||||||
virtual size_t _fillBuffer(uint8_t* buf, size_t maxLen) override;
|
size_t _fillBuffer(uint8_t* buf, size_t maxLen) override final;
|
||||||
};
|
};
|
||||||
|
|
||||||
class AsyncStreamResponse : public AsyncAbstractResponse {
|
class AsyncStreamResponse : public AsyncAbstractResponse {
|
||||||
@ -97,8 +99,8 @@ class AsyncStreamResponse : public AsyncAbstractResponse {
|
|||||||
public:
|
public:
|
||||||
AsyncStreamResponse(Stream& stream, const char* contentType, size_t len, AwsTemplateProcessor callback = nullptr);
|
AsyncStreamResponse(Stream& stream, const char* contentType, size_t len, AwsTemplateProcessor callback = nullptr);
|
||||||
AsyncStreamResponse(Stream& stream, const String& contentType, size_t len, AwsTemplateProcessor callback = nullptr) : AsyncStreamResponse(stream, contentType.c_str(), len, callback) {}
|
AsyncStreamResponse(Stream& stream, const String& contentType, size_t len, AwsTemplateProcessor callback = nullptr) : AsyncStreamResponse(stream, contentType.c_str(), len, callback) {}
|
||||||
bool _sourceValid() const { return !!(_content); }
|
bool _sourceValid() const override final { return !!(_content); }
|
||||||
virtual size_t _fillBuffer(uint8_t* buf, size_t maxLen) override;
|
size_t _fillBuffer(uint8_t* buf, size_t maxLen) override final;
|
||||||
};
|
};
|
||||||
|
|
||||||
class AsyncCallbackResponse : public AsyncAbstractResponse {
|
class AsyncCallbackResponse : public AsyncAbstractResponse {
|
||||||
@ -109,8 +111,8 @@ class AsyncCallbackResponse : public AsyncAbstractResponse {
|
|||||||
public:
|
public:
|
||||||
AsyncCallbackResponse(const char* contentType, size_t len, AwsResponseFiller callback, AwsTemplateProcessor templateCallback = nullptr);
|
AsyncCallbackResponse(const char* contentType, size_t len, AwsResponseFiller callback, AwsTemplateProcessor templateCallback = nullptr);
|
||||||
AsyncCallbackResponse(const String& contentType, size_t len, AwsResponseFiller callback, AwsTemplateProcessor templateCallback = nullptr) : AsyncCallbackResponse(contentType.c_str(), len, callback, templateCallback) {}
|
AsyncCallbackResponse(const String& contentType, size_t len, AwsResponseFiller callback, AwsTemplateProcessor templateCallback = nullptr) : AsyncCallbackResponse(contentType.c_str(), len, callback, templateCallback) {}
|
||||||
bool _sourceValid() const { return !!(_content); }
|
bool _sourceValid() const override final { return !!(_content); }
|
||||||
virtual size_t _fillBuffer(uint8_t* buf, size_t maxLen) override;
|
size_t _fillBuffer(uint8_t* buf, size_t maxLen) override final;
|
||||||
};
|
};
|
||||||
|
|
||||||
class AsyncChunkedResponse : public AsyncAbstractResponse {
|
class AsyncChunkedResponse : public AsyncAbstractResponse {
|
||||||
@ -121,8 +123,8 @@ class AsyncChunkedResponse : public AsyncAbstractResponse {
|
|||||||
public:
|
public:
|
||||||
AsyncChunkedResponse(const char* contentType, AwsResponseFiller callback, AwsTemplateProcessor templateCallback = nullptr);
|
AsyncChunkedResponse(const char* contentType, AwsResponseFiller callback, AwsTemplateProcessor templateCallback = nullptr);
|
||||||
AsyncChunkedResponse(const String& contentType, AwsResponseFiller callback, AwsTemplateProcessor templateCallback = nullptr) : AsyncChunkedResponse(contentType.c_str(), callback, templateCallback) {}
|
AsyncChunkedResponse(const String& contentType, AwsResponseFiller callback, AwsTemplateProcessor templateCallback = nullptr) : AsyncChunkedResponse(contentType.c_str(), callback, templateCallback) {}
|
||||||
bool _sourceValid() const { return !!(_content); }
|
bool _sourceValid() const override final { return !!(_content); }
|
||||||
virtual size_t _fillBuffer(uint8_t* buf, size_t maxLen) override;
|
size_t _fillBuffer(uint8_t* buf, size_t maxLen) override final;
|
||||||
};
|
};
|
||||||
|
|
||||||
class AsyncProgmemResponse : public AsyncAbstractResponse {
|
class AsyncProgmemResponse : public AsyncAbstractResponse {
|
||||||
@ -133,22 +135,19 @@ class AsyncProgmemResponse : public AsyncAbstractResponse {
|
|||||||
public:
|
public:
|
||||||
AsyncProgmemResponse(int code, const char* contentType, const uint8_t* content, size_t len, AwsTemplateProcessor callback = nullptr);
|
AsyncProgmemResponse(int code, const char* contentType, const uint8_t* content, size_t len, AwsTemplateProcessor callback = nullptr);
|
||||||
AsyncProgmemResponse(int code, const String& contentType, const uint8_t* content, size_t len, AwsTemplateProcessor callback = nullptr) : AsyncProgmemResponse(code, contentType.c_str(), content, len, callback) {}
|
AsyncProgmemResponse(int code, const String& contentType, const uint8_t* content, size_t len, AwsTemplateProcessor callback = nullptr) : AsyncProgmemResponse(code, contentType.c_str(), content, len, callback) {}
|
||||||
bool _sourceValid() const { return true; }
|
bool _sourceValid() const override final { return true; }
|
||||||
virtual size_t _fillBuffer(uint8_t* buf, size_t maxLen) override;
|
size_t _fillBuffer(uint8_t* buf, size_t maxLen) override final;
|
||||||
};
|
};
|
||||||
|
|
||||||
class cbuf;
|
|
||||||
|
|
||||||
class AsyncResponseStream : public AsyncAbstractResponse, public Print {
|
class AsyncResponseStream : public AsyncAbstractResponse, public Print {
|
||||||
private:
|
private:
|
||||||
std::unique_ptr<cbuf> _content;
|
StreamString _content;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
AsyncResponseStream(const char* contentType, size_t bufferSize);
|
AsyncResponseStream(const char* contentType, size_t bufferSize);
|
||||||
AsyncResponseStream(const String& contentType, size_t bufferSize) : AsyncResponseStream(contentType.c_str(), bufferSize) {}
|
AsyncResponseStream(const String& contentType, size_t bufferSize) : AsyncResponseStream(contentType.c_str(), bufferSize) {}
|
||||||
~AsyncResponseStream();
|
bool _sourceValid() const override final { return (_state < RESPONSE_END); }
|
||||||
bool _sourceValid() const { return (_state < RESPONSE_END); }
|
size_t _fillBuffer(uint8_t* buf, size_t maxLen) override final;
|
||||||
virtual size_t _fillBuffer(uint8_t* buf, size_t maxLen) override;
|
|
||||||
size_t write(const uint8_t* data, size_t len);
|
size_t write(const uint8_t* data, size_t len);
|
||||||
size_t write(uint8_t data);
|
size_t write(uint8_t data);
|
||||||
using Print::write;
|
using Print::write;
|
||||||
|
@ -20,7 +20,6 @@
|
|||||||
*/
|
*/
|
||||||
#include "ESPAsyncWebServer.h"
|
#include "ESPAsyncWebServer.h"
|
||||||
#include "WebResponseImpl.h"
|
#include "WebResponseImpl.h"
|
||||||
#include "cbuf.h"
|
|
||||||
|
|
||||||
using namespace asyncsrv;
|
using namespace asyncsrv;
|
||||||
|
|
||||||
@ -38,7 +37,6 @@ void* memchr(void* ptr, int ch, size_t count) {
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef ESP8266
|
|
||||||
const char* AsyncWebServerResponse::responseCodeToString(int code) {
|
const char* AsyncWebServerResponse::responseCodeToString(int code) {
|
||||||
switch (code) {
|
switch (code) {
|
||||||
case 100:
|
case 100:
|
||||||
@ -127,96 +125,6 @@ const char* AsyncWebServerResponse::responseCodeToString(int code) {
|
|||||||
return T_HTTP_CODE_ANY;
|
return T_HTTP_CODE_ANY;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#else // ESP8266
|
|
||||||
const __FlashStringHelper* AsyncWebServerResponse::responseCodeToString(int code) {
|
|
||||||
switch (code) {
|
|
||||||
case 100:
|
|
||||||
return FPSTR(T_HTTP_CODE_100);
|
|
||||||
case 101:
|
|
||||||
return FPSTR(T_HTTP_CODE_101);
|
|
||||||
case 200:
|
|
||||||
return FPSTR(T_HTTP_CODE_200);
|
|
||||||
case 201:
|
|
||||||
return FPSTR(T_HTTP_CODE_201);
|
|
||||||
case 202:
|
|
||||||
return FPSTR(T_HTTP_CODE_202);
|
|
||||||
case 203:
|
|
||||||
return FPSTR(T_HTTP_CODE_203);
|
|
||||||
case 204:
|
|
||||||
return FPSTR(T_HTTP_CODE_204);
|
|
||||||
case 205:
|
|
||||||
return FPSTR(T_HTTP_CODE_205);
|
|
||||||
case 206:
|
|
||||||
return FPSTR(T_HTTP_CODE_206);
|
|
||||||
case 300:
|
|
||||||
return FPSTR(T_HTTP_CODE_300);
|
|
||||||
case 301:
|
|
||||||
return FPSTR(T_HTTP_CODE_301);
|
|
||||||
case 302:
|
|
||||||
return FPSTR(T_HTTP_CODE_302);
|
|
||||||
case 303:
|
|
||||||
return FPSTR(T_HTTP_CODE_303);
|
|
||||||
case 304:
|
|
||||||
return FPSTR(T_HTTP_CODE_304);
|
|
||||||
case 305:
|
|
||||||
return FPSTR(T_HTTP_CODE_305);
|
|
||||||
case 307:
|
|
||||||
return FPSTR(T_HTTP_CODE_307);
|
|
||||||
case 400:
|
|
||||||
return FPSTR(T_HTTP_CODE_400);
|
|
||||||
case 401:
|
|
||||||
return FPSTR(T_HTTP_CODE_401);
|
|
||||||
case 402:
|
|
||||||
return FPSTR(T_HTTP_CODE_402);
|
|
||||||
case 403:
|
|
||||||
return FPSTR(T_HTTP_CODE_403);
|
|
||||||
case 404:
|
|
||||||
return FPSTR(T_HTTP_CODE_404);
|
|
||||||
case 405:
|
|
||||||
return FPSTR(T_HTTP_CODE_405);
|
|
||||||
case 406:
|
|
||||||
return FPSTR(T_HTTP_CODE_406);
|
|
||||||
case 407:
|
|
||||||
return FPSTR(T_HTTP_CODE_407);
|
|
||||||
case 408:
|
|
||||||
return FPSTR(T_HTTP_CODE_408);
|
|
||||||
case 409:
|
|
||||||
return FPSTR(T_HTTP_CODE_409);
|
|
||||||
case 410:
|
|
||||||
return FPSTR(T_HTTP_CODE_410);
|
|
||||||
case 411:
|
|
||||||
return FPSTR(T_HTTP_CODE_411);
|
|
||||||
case 412:
|
|
||||||
return FPSTR(T_HTTP_CODE_412);
|
|
||||||
case 413:
|
|
||||||
return FPSTR(T_HTTP_CODE_413);
|
|
||||||
case 414:
|
|
||||||
return FPSTR(T_HTTP_CODE_414);
|
|
||||||
case 415:
|
|
||||||
return FPSTR(T_HTTP_CODE_415);
|
|
||||||
case 416:
|
|
||||||
return FPSTR(T_HTTP_CODE_416);
|
|
||||||
case 417:
|
|
||||||
return FPSTR(T_HTTP_CODE_417);
|
|
||||||
case 429:
|
|
||||||
return FPSTR(T_HTTP_CODE_429);
|
|
||||||
case 500:
|
|
||||||
return FPSTR(T_HTTP_CODE_500);
|
|
||||||
case 501:
|
|
||||||
return FPSTR(T_HTTP_CODE_501);
|
|
||||||
case 502:
|
|
||||||
return FPSTR(T_HTTP_CODE_502);
|
|
||||||
case 503:
|
|
||||||
return FPSTR(T_HTTP_CODE_503);
|
|
||||||
case 504:
|
|
||||||
return FPSTR(T_HTTP_CODE_504);
|
|
||||||
case 505:
|
|
||||||
return FPSTR(T_HTTP_CODE_505);
|
|
||||||
default:
|
|
||||||
return FPSTR(T_HTTP_CODE_ANY);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif // ESP8266
|
|
||||||
|
|
||||||
AsyncWebServerResponse::AsyncWebServerResponse()
|
AsyncWebServerResponse::AsyncWebServerResponse()
|
||||||
: _code(0), _contentType(), _contentLength(0), _sendContentLength(true), _chunked(false), _headLength(0), _sentLength(0), _ackedLength(0), _writtenLength(0), _state(RESPONSE_SETUP) {
|
: _code(0), _contentType(), _contentLength(0), _sendContentLength(true), _chunked(false), _headLength(0), _sentLength(0), _ackedLength(0), _writtenLength(0), _state(RESPONSE_SETUP) {
|
||||||
@ -225,8 +133,6 @@ AsyncWebServerResponse::AsyncWebServerResponse()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
AsyncWebServerResponse::~AsyncWebServerResponse() = default;
|
|
||||||
|
|
||||||
void AsyncWebServerResponse::setCode(int code) {
|
void AsyncWebServerResponse::setCode(int code) {
|
||||||
if (_state == RESPONSE_SETUP)
|
if (_state == RESPONSE_SETUP)
|
||||||
_code = code;
|
_code = code;
|
||||||
@ -648,11 +554,6 @@ size_t AsyncAbstractResponse::_fillBufferAndProcessTemplates(uint8_t* data, size
|
|||||||
* File Response
|
* File Response
|
||||||
* */
|
* */
|
||||||
|
|
||||||
AsyncFileResponse::~AsyncFileResponse() {
|
|
||||||
if (_content)
|
|
||||||
_content.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
void AsyncFileResponse::_setContentTypeFromPath(const String& path) {
|
void AsyncFileResponse::_setContentTypeFromPath(const String& path) {
|
||||||
#if HAVE_EXTERN_GET_Content_Type_FUNCTION
|
#if HAVE_EXTERN_GET_Content_Type_FUNCTION
|
||||||
#ifndef ESP8266
|
#ifndef ESP8266
|
||||||
@ -868,24 +769,17 @@ AsyncResponseStream::AsyncResponseStream(const char* contentType, size_t bufferS
|
|||||||
_code = 200;
|
_code = 200;
|
||||||
_contentLength = 0;
|
_contentLength = 0;
|
||||||
_contentType = contentType;
|
_contentType = contentType;
|
||||||
_content = std::unique_ptr<cbuf>(new cbuf(bufferSize)); // std::make_unique<cbuf>(bufferSize);
|
_content.reserve(bufferSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
AsyncResponseStream::~AsyncResponseStream() = default;
|
|
||||||
|
|
||||||
size_t AsyncResponseStream::_fillBuffer(uint8_t* buf, size_t maxLen) {
|
size_t AsyncResponseStream::_fillBuffer(uint8_t* buf, size_t maxLen) {
|
||||||
return _content->read((char*)buf, maxLen);
|
return _content.readBytes((char*)buf, maxLen);
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t AsyncResponseStream::write(const uint8_t* data, size_t len) {
|
size_t AsyncResponseStream::write(const uint8_t* data, size_t len) {
|
||||||
if (_started())
|
if (_started())
|
||||||
return 0;
|
return 0;
|
||||||
|
size_t written = _content.write(data, len);
|
||||||
if (len > _content->room()) {
|
|
||||||
size_t needed = len - _content->room();
|
|
||||||
_content->resizeAdd(needed);
|
|
||||||
}
|
|
||||||
size_t written = _content->write((const char*)data, len);
|
|
||||||
_contentLength += written;
|
_contentLength += written;
|
||||||
return written;
|
return written;
|
||||||
}
|
}
|
||||||
|
283
src/literals.h
283
src/literals.h
@ -4,47 +4,79 @@ namespace asyncsrv {
|
|||||||
|
|
||||||
static constexpr const char* empty = "";
|
static constexpr const char* empty = "";
|
||||||
|
|
||||||
#ifndef ESP8622
|
static constexpr const char* T__opaque = "\", opaque=\"";
|
||||||
static constexpr const char* T_100_CONTINUE = "100-continue";
|
static constexpr const char* T_100_CONTINUE = "100-continue";
|
||||||
static constexpr const char* T_ACCEPT = "Accept";
|
static constexpr const char* T_13 = "13";
|
||||||
static constexpr const char* T_Accept_Ranges = "Accept-Ranges";
|
static constexpr const char* T_ACCEPT = "accept";
|
||||||
|
static constexpr const char* T_Accept_Ranges = "accept-ranges";
|
||||||
static constexpr const char* T_app_xform_urlencoded = "application/x-www-form-urlencoded";
|
static constexpr const char* T_app_xform_urlencoded = "application/x-www-form-urlencoded";
|
||||||
static constexpr const char* T_AUTH = "Authorization";
|
static constexpr const char* T_AUTH = "authorization";
|
||||||
static constexpr const char* T_BASIC = "Basic";
|
static constexpr const char* T_auth_nonce = "\", qop=\"auth\", nonce=\"";
|
||||||
static constexpr const char* T_BASIC_REALM = "Basic realm=\"";
|
static constexpr const char* T_BASIC = "basic";
|
||||||
static constexpr const char* T_LOGIN_REQ = "Login Required";
|
static constexpr const char* T_BASIC_REALM = "basic realm=\"";
|
||||||
|
static constexpr const char* T_BEARER = "bearer";
|
||||||
static constexpr const char* T_BODY = "body";
|
static constexpr const char* T_BODY = "body";
|
||||||
static constexpr const char* T_Cache_Control = "Cache-Control";
|
static constexpr const char* T_Cache_Control = "cache-control";
|
||||||
static constexpr const char* T_chunked = "chunked";
|
static constexpr const char* T_chunked = "chunked";
|
||||||
static constexpr const char* T_close = "close";
|
static constexpr const char* T_close = "close";
|
||||||
static constexpr const char* T_Connection = "Connection";
|
static constexpr const char* T_cnonce = "cnonce";
|
||||||
static constexpr const char* T_Content_Disposition = "Content-Disposition";
|
static constexpr const char* T_Connection = "connection";
|
||||||
static constexpr const char* T_Content_Encoding = "Content-Encoding";
|
static constexpr const char* T_Content_Disposition = "content-disposition";
|
||||||
static constexpr const char* T_Content_Length = "Content-Length";
|
static constexpr const char* T_Content_Encoding = "content-encoding";
|
||||||
static constexpr const char* T_Content_Type = "Content-Type";
|
static constexpr const char* T_Content_Length = "content-length";
|
||||||
static constexpr const char* T_Cookie = "Cookie";
|
static constexpr const char* T_Content_Type = "content-type";
|
||||||
static constexpr const char* T_DIGEST = "Digest";
|
static constexpr const char* T_Cookie = "cookie";
|
||||||
static constexpr const char* T_DIGEST_ = "Digest ";
|
static constexpr const char* T_CORS_ACAC = "access-control-allow-credentials";
|
||||||
static constexpr const char* T_BEARER = "Bearer";
|
static constexpr const char* T_CORS_ACAH = "access-control-allow-headers";
|
||||||
static constexpr const char* T_ETag = "ETag";
|
static constexpr const char* T_CORS_ACAM = "access-control-allow-methods";
|
||||||
static constexpr const char* T_EXPECT = "Expect";
|
static constexpr const char* T_CORS_ACAO = "access-control-allow-origin";
|
||||||
|
static constexpr const char* T_CORS_ACMA = "access-control-max-age";
|
||||||
|
static constexpr const char* T_CORS_O = "origin";
|
||||||
|
static constexpr const char* T_data_ = "data: ";
|
||||||
|
static constexpr const char* T_DIGEST = "digest";
|
||||||
|
static constexpr const char* T_DIGEST_ = "digest ";
|
||||||
|
static constexpr const char* T_ETag = "etag";
|
||||||
|
static constexpr const char* T_event_ = "event: ";
|
||||||
|
static constexpr const char* T_EXPECT = "expect";
|
||||||
|
static constexpr const char* T_FALSE = "false";
|
||||||
|
static constexpr const char* T_filename = "filename";
|
||||||
|
static constexpr const char* T_gzip = "gzip";
|
||||||
|
static constexpr const char* T_Host = "host";
|
||||||
static constexpr const char* T_HTTP_1_0 = "HTTP/1.0";
|
static constexpr const char* T_HTTP_1_0 = "HTTP/1.0";
|
||||||
static constexpr const char* T_HTTP_100_CONT = "HTTP/1.1 100 Continue\r\n\r\n";
|
static constexpr const char* T_HTTP_100_CONT = "HTTP/1.1 100 Continue\r\n\r\n";
|
||||||
static constexpr const char* T_IMS = "If-Modified-Since";
|
static constexpr const char* T_id__ = "id: ";
|
||||||
static constexpr const char* T_INM = "If-None-Match";
|
static constexpr const char* T_IMS = "if-modified-since";
|
||||||
|
static constexpr const char* T_INM = "if-none-match";
|
||||||
static constexpr const char* T_keep_alive = "keep-alive";
|
static constexpr const char* T_keep_alive = "keep-alive";
|
||||||
static constexpr const char* T_Last_Event_ID = "Last-Event-ID";
|
static constexpr const char* T_Last_Event_ID = "last-event-id";
|
||||||
static constexpr const char* T_Last_Modified = "Last-Modified";
|
static constexpr const char* T_Last_Modified = "last-modified";
|
||||||
static constexpr const char* T_LOCATION = "Location";
|
static constexpr const char* T_LOCATION = "location";
|
||||||
|
static constexpr const char* T_LOGIN_REQ = "Login Required";
|
||||||
static constexpr const char* T_MULTIPART_ = "multipart/";
|
static constexpr const char* T_MULTIPART_ = "multipart/";
|
||||||
|
static constexpr const char* T_name = "name";
|
||||||
|
static constexpr const char* T_nc = "nc";
|
||||||
static constexpr const char* T_no_cache = "no-cache";
|
static constexpr const char* T_no_cache = "no-cache";
|
||||||
|
static constexpr const char* T_nonce = "nonce";
|
||||||
static constexpr const char* T_none = "none";
|
static constexpr const char* T_none = "none";
|
||||||
static constexpr const char* T_UPGRADE = "Upgrade";
|
static constexpr const char* T_opaque = "opaque";
|
||||||
|
static constexpr const char* T_qop = "qop";
|
||||||
|
static constexpr const char* T_realm = "realm";
|
||||||
|
static constexpr const char* T_realm__ = "realm=\"";
|
||||||
|
static constexpr const char* T_response = "response";
|
||||||
|
static constexpr const char* T_retry_ = "retry: ";
|
||||||
|
static constexpr const char* T_retry_after = "retry-after";
|
||||||
|
static constexpr const char* T_rn = "\r\n";
|
||||||
|
static constexpr const char* T_rnrn = "\r\n\r\n";
|
||||||
|
static constexpr const char* T_Transfer_Encoding = "transfer-encoding";
|
||||||
|
static constexpr const char* T_TRUE = "true";
|
||||||
|
static constexpr const char* T_UPGRADE = "upgrade";
|
||||||
|
static constexpr const char* T_uri = "uri";
|
||||||
|
static constexpr const char* T_username = "username";
|
||||||
static constexpr const char* T_WS = "websocket";
|
static constexpr const char* T_WS = "websocket";
|
||||||
static constexpr const char* T_WWW_AUTH = "WWW-Authenticate";
|
static constexpr const char* T_WWW_AUTH = "www-authenticate";
|
||||||
static constexpr const char* T_Transfer_Encoding = "Transfer-Encoding";
|
|
||||||
|
|
||||||
// HTTP Methods
|
// HTTP Methods
|
||||||
|
|
||||||
static constexpr const char* T_ANY = "ANY";
|
static constexpr const char* T_ANY = "ANY";
|
||||||
static constexpr const char* T_GET = "GET";
|
static constexpr const char* T_GET = "GET";
|
||||||
static constexpr const char* T_POST = "POST";
|
static constexpr const char* T_POST = "POST";
|
||||||
@ -147,201 +179,4 @@ static constexpr const char* T_HTTP_CODE_504 = "Gateway Time-out";
|
|||||||
static constexpr const char* T_HTTP_CODE_505 = "HTTP Version not supported";
|
static constexpr const char* T_HTTP_CODE_505 = "HTTP Version not supported";
|
||||||
static constexpr const char* T_HTTP_CODE_ANY = "Unknown code";
|
static constexpr const char* T_HTTP_CODE_ANY = "Unknown code";
|
||||||
|
|
||||||
// other
|
|
||||||
static constexpr const char* T__opaque = "\", opaque=\"";
|
|
||||||
static constexpr const char* T_13 = "13";
|
|
||||||
static constexpr const char* T_auth_nonce = "\", qop=\"auth\", nonce=\"";
|
|
||||||
static constexpr const char* T_cnonce = "cnonce";
|
|
||||||
static constexpr const char* T_data_ = "data: ";
|
|
||||||
static constexpr const char* T_event_ = "event: ";
|
|
||||||
static constexpr const char* T_filename = "filename";
|
|
||||||
static constexpr const char* T_gzip = "gzip";
|
|
||||||
static constexpr const char* T_Host = "Host";
|
|
||||||
static constexpr const char* T_id__ = "id: ";
|
|
||||||
static constexpr const char* T_name = "name";
|
|
||||||
static constexpr const char* T_nc = "nc";
|
|
||||||
static constexpr const char* T_nonce = "nonce";
|
|
||||||
static constexpr const char* T_opaque = "opaque";
|
|
||||||
static constexpr const char* T_qop = "qop";
|
|
||||||
static constexpr const char* T_realm = "realm";
|
|
||||||
static constexpr const char* T_realm__ = "realm=\"";
|
|
||||||
static constexpr const char* T_response = "response";
|
|
||||||
static constexpr const char* T_retry_ = "retry: ";
|
|
||||||
static constexpr const char* T_rn = "\r\n";
|
|
||||||
static constexpr const char* T_rnrn = "\r\n\r\n";
|
|
||||||
static constexpr const char* T_uri = "uri";
|
|
||||||
static constexpr const char* T_username = "username";
|
|
||||||
|
|
||||||
|
|
||||||
#else // ESP8622
|
|
||||||
|
|
||||||
static const char T_100_CONTINUE[] PROGMEM = "100-continue";
|
|
||||||
static const char T_ACCEPT[] PROGMEM = "Accept";
|
|
||||||
static const char T_Accept_Ranges[] PROGMEM = "Accept-Ranges";
|
|
||||||
static const char T_app_xform_urlencoded[] PROGMEM = "application/x-www-form-urlencoded";
|
|
||||||
static const char T_AUTH[] PROGMEM = "Authorization";
|
|
||||||
static const char T_BASIC[] PROGMEM = "Basic";
|
|
||||||
static const char T_BASIC_REALM[] PROGMEM = "Basic realm=\"";
|
|
||||||
static const char T_LOGIN_REQ[] PROGMEM = "Login Required";
|
|
||||||
static const char T_BODY[] PROGMEM = "body";
|
|
||||||
static const char T_Cache_Control[] PROGMEM = "Cache-Control";
|
|
||||||
static const char T_chunked[] PROGMEM = "chunked";
|
|
||||||
static const char T_close[] PROGMEM = "close";
|
|
||||||
static const char T_Connection[] PROGMEM = "Connection";
|
|
||||||
static const char T_Content_Disposition[] PROGMEM = "Content-Disposition";
|
|
||||||
static const char T_Content_Encoding[] PROGMEM = "Content-Encoding";
|
|
||||||
static const char T_Content_Length[] PROGMEM = "Content-Length";
|
|
||||||
static const char T_Content_Type[] PROGMEM = "Content-Type";
|
|
||||||
static const char T_Cookie[] PROGMEM = "Cookie";
|
|
||||||
static const char T_DIGEST[] PROGMEM = "Digest";
|
|
||||||
static const char T_DIGEST_[] PROGMEM = "Digest ";
|
|
||||||
static const char T_BEARER[] PROGMEM = "Bearer";
|
|
||||||
static const char T_ETag[] PROGMEM = "ETag";
|
|
||||||
static const char T_EXPECT[] PROGMEM = "Expect";
|
|
||||||
static const char T_HTTP_1_0[] PROGMEM = "HTTP/1.0";
|
|
||||||
static const char T_HTTP_100_CONT[] PROGMEM = "HTTP/1.1 100 Continue\r\n\r\n";
|
|
||||||
static const char T_IMS[] PROGMEM = "If-Modified-Since";
|
|
||||||
static const char T_INM[] PROGMEM = "If-None-Match";
|
|
||||||
static const char T_keep_alive[] PROGMEM = "keep-alive";
|
|
||||||
static const char T_Last_Event_ID[] PROGMEM = "Last-Event-ID";
|
|
||||||
static const char T_Last_Modified[] PROGMEM = "Last-Modified";
|
|
||||||
static const char T_LOCATION[] PROGMEM = "Location";
|
|
||||||
static const char T_MULTIPART_[] PROGMEM = "multipart/";
|
|
||||||
static const char T_no_cache[] PROGMEM = "no-cache";
|
|
||||||
static const char T_none[] PROGMEM = "none";
|
|
||||||
static const char T_UPGRADE[] PROGMEM = "Upgrade";
|
|
||||||
static const char T_WS[] PROGMEM = "websocket";
|
|
||||||
static const char T_WWW_AUTH[] PROGMEM = "WWW-Authenticate";
|
|
||||||
static const char T_Transfer_Encoding[] PROGMEM = "Transfer-Encoding";
|
|
||||||
|
|
||||||
// HTTP Methods
|
|
||||||
static const char T_ANY[] PROGMEM = "ANY";
|
|
||||||
static const char T_GET[] PROGMEM = "GET";
|
|
||||||
static const char T_POST[] PROGMEM = "POST";
|
|
||||||
static const char T_PUT[] PROGMEM = "PUT";
|
|
||||||
static const char T_DELETE[] PROGMEM = "DELETE";
|
|
||||||
static const char T_PATCH[] PROGMEM = "PATCH";
|
|
||||||
static const char T_HEAD[] PROGMEM = "HEAD";
|
|
||||||
static const char T_OPTIONS[] PROGMEM = "OPTIONS";
|
|
||||||
static const char T_UNKNOWN[] PROGMEM = "UNKNOWN";
|
|
||||||
|
|
||||||
// Req content types
|
|
||||||
static const char T_RCT_NOT_USED[] PROGMEM = "RCT_NOT_USED";
|
|
||||||
static const char T_RCT_DEFAULT[] PROGMEM = "RCT_DEFAULT";
|
|
||||||
static const char T_RCT_HTTP[] PROGMEM = "RCT_HTTP";
|
|
||||||
static const char T_RCT_WS[] PROGMEM = "RCT_WS";
|
|
||||||
static const char T_RCT_EVENT[] PROGMEM = "RCT_EVENT";
|
|
||||||
static const char T_ERROR[] PROGMEM = "ERROR";
|
|
||||||
|
|
||||||
// extentions & MIME-Types
|
|
||||||
static const char T__css[] PROGMEM = ".css";
|
|
||||||
static const char T__eot[] PROGMEM = ".eot";
|
|
||||||
static const char T__gif[] PROGMEM = ".gif";
|
|
||||||
static const char T__gz[] PROGMEM = ".gz";
|
|
||||||
static const char T__htm[] PROGMEM = ".htm";
|
|
||||||
static const char T__html[] PROGMEM = ".html";
|
|
||||||
static const char T__ico[] PROGMEM = ".ico";
|
|
||||||
static const char T__jpg[] PROGMEM = ".jpg";
|
|
||||||
static const char T__js[] PROGMEM = ".js";
|
|
||||||
static const char T__json[] PROGMEM = ".json";
|
|
||||||
static const char T__pdf[] PROGMEM = ".pdf";
|
|
||||||
static const char T__png[] PROGMEM = ".png";
|
|
||||||
static const char T__svg[] PROGMEM = ".svg";
|
|
||||||
static const char T__ttf[] PROGMEM = ".ttf";
|
|
||||||
static const char T__woff[] PROGMEM = ".woff";
|
|
||||||
static const char T__woff2[] PROGMEM = ".woff2";
|
|
||||||
static const char T__xml[] PROGMEM = ".xml";
|
|
||||||
static const char T__zip[] PROGMEM = ".zip";
|
|
||||||
static const char T_application_javascript[] PROGMEM = "application/javascript";
|
|
||||||
static const char T_application_json[] PROGMEM = "application/json";
|
|
||||||
static const char T_application_msgpack[] PROGMEM = "application/msgpack";
|
|
||||||
static const char T_application_pdf[] PROGMEM = "application/pdf";
|
|
||||||
static const char T_application_x_gzip[] PROGMEM = "application/x-gzip";
|
|
||||||
static const char T_application_zip[] PROGMEM = "application/zip";
|
|
||||||
static const char T_font_eot[] PROGMEM = "font/eot";
|
|
||||||
static const char T_font_ttf[] PROGMEM = "font/ttf";
|
|
||||||
static const char T_font_woff[] PROGMEM = "font/woff";
|
|
||||||
static const char T_font_woff2[] PROGMEM = "font/woff2";
|
|
||||||
static const char T_image_gif[] PROGMEM = "image/gif";
|
|
||||||
static const char T_image_jpeg[] PROGMEM = "image/jpeg";
|
|
||||||
static const char T_image_png[] PROGMEM = "image/png";
|
|
||||||
static const char T_image_svg_xml[] PROGMEM = "image/svg+xml";
|
|
||||||
static const char T_image_x_icon[] PROGMEM = "image/x-icon";
|
|
||||||
static const char T_text_css[] PROGMEM = "text/css";
|
|
||||||
static const char T_text_event_stream[] PROGMEM = "text/event-stream";
|
|
||||||
static const char T_text_html[] PROGMEM = "text/html";
|
|
||||||
static const char T_text_plain[] PROGMEM = "text/plain";
|
|
||||||
static const char T_text_xml[] PROGMEM = "text/xml";
|
|
||||||
|
|
||||||
// Responce codes
|
|
||||||
static const char T_HTTP_CODE_100[] PROGMEM = "Continue";
|
|
||||||
static const char T_HTTP_CODE_101[] PROGMEM = "Switching Protocols";
|
|
||||||
static const char T_HTTP_CODE_200[] PROGMEM = "OK";
|
|
||||||
static const char T_HTTP_CODE_201[] PROGMEM = "Created";
|
|
||||||
static const char T_HTTP_CODE_202[] PROGMEM = "Accepted";
|
|
||||||
static const char T_HTTP_CODE_203[] PROGMEM = "Non-Authoritative Information";
|
|
||||||
static const char T_HTTP_CODE_204[] PROGMEM = "No Content";
|
|
||||||
static const char T_HTTP_CODE_205[] PROGMEM = "Reset Content";
|
|
||||||
static const char T_HTTP_CODE_206[] PROGMEM = "Partial Content";
|
|
||||||
static const char T_HTTP_CODE_300[] PROGMEM = "Multiple Choices";
|
|
||||||
static const char T_HTTP_CODE_301[] PROGMEM = "Moved Permanently";
|
|
||||||
static const char T_HTTP_CODE_302[] PROGMEM = "Found";
|
|
||||||
static const char T_HTTP_CODE_303[] PROGMEM = "See Other";
|
|
||||||
static const char T_HTTP_CODE_304[] PROGMEM = "Not Modified";
|
|
||||||
static const char T_HTTP_CODE_305[] PROGMEM = "Use Proxy";
|
|
||||||
static const char T_HTTP_CODE_307[] PROGMEM = "Temporary Redirect";
|
|
||||||
static const char T_HTTP_CODE_400[] PROGMEM = "Bad Request";
|
|
||||||
static const char T_HTTP_CODE_401[] PROGMEM = "Unauthorized";
|
|
||||||
static const char T_HTTP_CODE_402[] PROGMEM = "Payment Required";
|
|
||||||
static const char T_HTTP_CODE_403[] PROGMEM = "Forbidden";
|
|
||||||
static const char T_HTTP_CODE_404[] PROGMEM = "Not Found";
|
|
||||||
static const char T_HTTP_CODE_405[] PROGMEM = "Method Not Allowed";
|
|
||||||
static const char T_HTTP_CODE_406[] PROGMEM = "Not Acceptable";
|
|
||||||
static const char T_HTTP_CODE_407[] PROGMEM = "Proxy Authentication Required";
|
|
||||||
static const char T_HTTP_CODE_408[] PROGMEM = "Request Time-out";
|
|
||||||
static const char T_HTTP_CODE_409[] PROGMEM = "Conflict";
|
|
||||||
static const char T_HTTP_CODE_410[] PROGMEM = "Gone";
|
|
||||||
static const char T_HTTP_CODE_411[] PROGMEM = "Length Required";
|
|
||||||
static const char T_HTTP_CODE_412[] PROGMEM = "Precondition Failed";
|
|
||||||
static const char T_HTTP_CODE_413[] PROGMEM = "Request Entity Too Large";
|
|
||||||
static const char T_HTTP_CODE_414[] PROGMEM = "Request-URI Too Large";
|
|
||||||
static const char T_HTTP_CODE_415[] PROGMEM = "Unsupported Media Type";
|
|
||||||
static const char T_HTTP_CODE_416[] PROGMEM = "Requested range not satisfiable";
|
|
||||||
static const char T_HTTP_CODE_417[] PROGMEM = "Expectation Failed";
|
|
||||||
static const char T_HTTP_CODE_429[] PROGMEM = "Too Many Requests";
|
|
||||||
static const char T_HTTP_CODE_500[] PROGMEM = "Internal Server Error";
|
|
||||||
static const char T_HTTP_CODE_501[] PROGMEM = "Not Implemented";
|
|
||||||
static const char T_HTTP_CODE_502[] PROGMEM = "Bad Gateway";
|
|
||||||
static const char T_HTTP_CODE_503[] PROGMEM = "Service Unavailable";
|
|
||||||
static const char T_HTTP_CODE_504[] PROGMEM = "Gateway Time-out";
|
|
||||||
static const char T_HTTP_CODE_505[] PROGMEM = "HTTP Version not supported";
|
|
||||||
static const char T_HTTP_CODE_ANY[] PROGMEM = "Unknown code";
|
|
||||||
|
|
||||||
// other
|
|
||||||
static const char T__opaque[] PROGMEM = "\", opaque=\"";
|
|
||||||
static const char T_13[] PROGMEM = "13";
|
|
||||||
static const char T_auth_nonce[] PROGMEM = "\", qop=\"auth\", nonce=\"";
|
|
||||||
static const char T_cnonce[] PROGMEM = "cnonce";
|
|
||||||
static const char T_data_[] PROGMEM = "data: ";
|
|
||||||
static const char T_event_[] PROGMEM = "event: ";
|
|
||||||
static const char T_filename[] PROGMEM = "filename";
|
|
||||||
static const char T_gzip[] PROGMEM = "gzip";
|
|
||||||
static const char T_Host[] PROGMEM = "Host";
|
|
||||||
static const char T_id__[] PROGMEM = "id: ";
|
|
||||||
static const char T_name[] PROGMEM = "name";
|
|
||||||
static const char T_nc[] PROGMEM = "nc";
|
|
||||||
static const char T_nonce[] PROGMEM = "nonce";
|
|
||||||
static const char T_opaque[] PROGMEM = "opaque";
|
|
||||||
static const char T_qop[] PROGMEM = "qop";
|
|
||||||
static const char T_realm[] PROGMEM = "realm";
|
|
||||||
static const char T_realm__[] PROGMEM = "realm=\"";
|
|
||||||
static const char T_response[] PROGMEM = "response";
|
|
||||||
static const char T_retry_[] PROGMEM = "retry: ";
|
|
||||||
static const char T_rn[] PROGMEM = "\r\n";
|
|
||||||
static const char T_rnrn[] PROGMEM = "\r\n\r\n";
|
|
||||||
static const char T_uri[] PROGMEM = "uri";
|
|
||||||
static const char T_username[] PROGMEM = "username";
|
|
||||||
|
|
||||||
#endif // ESP8622
|
|
||||||
|
|
||||||
} // namespace asyncsrv {}
|
} // namespace asyncsrv {}
|
||||||
|
Loading…
Reference in New Issue
Block a user