Skip to content

Commit

Permalink
Revert "ESP_Async_WebServer"
Browse files Browse the repository at this point in the history
This reverts commit 2ef9fb5.
  • Loading branch information
LKosoj committed Jan 18, 2025
1 parent 686b447 commit 24c8af6
Show file tree
Hide file tree
Showing 11 changed files with 181 additions and 243 deletions.
94 changes: 34 additions & 60 deletions libraries/ESP_Async_WebServer/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,11 @@ This fork is based on [yubox-node-org/ESPAsyncWebServer](https://github.com/yubo
- [Changes in this fork](#changes-in-this-fork)
- [Dependencies](#dependencies)
- [Performance](#performance)
- [Important recommendations for build options](#important-recommendations-for-build-options)
- [Important recommendations](#important-recommendations)
- [`AsyncWebSocketMessageBuffer` and `makeBuffer()`](#asyncwebsocketmessagebuffer-and-makebuffer)
- [How to replace a response](#how-to-replace-a-response)
- [How to use Middleware](#how-to-use-middleware)
- [How to use authentication with AsyncAuthenticationMiddleware](#how-to-use-authentication-with-authenticationmiddleware)
- [How to use authentication with AuthenticationMiddleware](#how-to-use-authentication-with-authenticationmiddleware)
- [Migration to Middleware to improve performance and memory usage](#migration-to-middleware-to-improve-performance-and-memory-usage)
- [Original Documentation](#original-documentation)

Expand All @@ -48,7 +48,6 @@ This fork is based on [yubox-node-org/ESPAsyncWebServer](https://github.com/yubo
- (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) `SSE_MAX_QUEUED_MESSAGES` to control the maximum number of messages that can be queued for a SSE client
- (perf) `WS_MAX_QUEUED_MESSAGES`: control the maximum number of messages that can be queued for a Websocket client
- (perf) in-flight buffer control and queue congestion avoidance to help to improve parallel connections handling, high volume data transfers and mitigate poor implemeneted slow user-code callbacks delayes on connctions handling
- (perf) Code size improvements
- (perf) Lot of code cleanup and optimizations
- (perf) Performance improvements in terms of memory, speed and size
Expand All @@ -57,7 +56,7 @@ This fork is based on [yubox-node-org/ESPAsyncWebServer](https://github.com/yubo

## WARNING: Important notes about future version 4.x

This ESPAsyncWebServer fork is now at version 3.x, where we try to keep the API compatibility with original project as much as possible.
This ESPAsyncWebServer fork is now at version 3.x.

Next version 4.x will:

Expand All @@ -69,21 +68,20 @@ So if you need one of these feature, you will have to stick with 3.x or another

## 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.
**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.6.0
lib_deps = mathieucarbou/ESPAsyncWebServer @ 3.4.5
```

**Dependencies:**

- **ESP32 with AsyncTCP**: `mathieucarbou/AsyncTCP @ 3.3.2`
Arduino IDE: [https://github.com/mathieucarbou/AsyncTCP#v3.3.2](https://github.com/mathieucarbou/AsyncTCP/releases)
- **ESP32 with AsyncTCP**: `mathieucarbou/AsyncTCP @ 3.3.1`
Arduino IDE: [https://github.com/mathieucarbou/AsyncTCP#v3.3.1](https://github.com/mathieucarbou/AsyncTCP/releases)

- **ESP32 with AsyncTCPSock**: `https://github.com/mathieucarbou/AsyncTCPSock/archive/refs/tags/v1.0.3-dev.zip`

Expand All @@ -101,24 +99,24 @@ AsyncTCPSock can be used instead of AsyncTCP by excluding AsyncTCP from the libr
lib_compat_mode = strict
lib_ldf_mode = chain
lib_deps =
; mathieucarbou/AsyncTCP @ 3.3.2
; mathieucarbou/AsyncTCP @ 3.3.1
https://github.com/mathieucarbou/AsyncTCPSock/archive/refs/tags/v1.0.3-dev.zip
mathieucarbou/ESPAsyncWebServer @ 3.6.0
mathieucarbou/ESPAsyncWebServer @ 3.4.5
lib_ignore =
AsyncTCP
mathieucarbou/AsyncTCP
```

## Performance

Performance of `mathieucarbou/ESPAsyncWebServer @ 3.6.0`:
Performance of `mathieucarbou/ESPAsyncWebServer @ 3.4.5`:

```bash
> brew install autocannon
> autocannon -c 10 -w 10 -d 20 http://192.168.4.1
```

With `mathieucarbou/AsyncTCP @ 3.3.2`
With `mathieucarbou/AsyncTCP @ 3.3.1`

[![](https://mathieu.carbou.me/ESPAsyncWebServer/perf-c10.png)](https://mathieu.carbou.me/ESPAsyncWebServer/perf-c10.png)

Expand Down Expand Up @@ -160,41 +158,26 @@ Test is running for 20 seconds with 10 connections.
// Total: 2038 events, 509.50 events / second
```

## Important recommendations for build options
## Important recommendations

Most of the crashes are caused by improper use or configuration of the AsyncTCP library used for the project.
Here are some recommendations to avoid them and build-time flags you can change.

`CONFIG_ASYNC_TCP_MAX_ACK_TIME` - defines a timeout for TCP connection to be considered alive when waiting for data.
In some bad network conditions you might consider increasing it.

`CONFIG_ASYNC_TCP_QUEUE_SIZE` - defines the length of the queue for events related to connections handling.
Both the server and AsyncTCP library in this fork were optimized to control the queue automatically. Do NOT try blindly increasing the queue size, it does not help you in a way you might think it is. If you receive debug messages about queue throttling, try to optimize your server callbaks code to execute as fast as possible.
Read #165 thread, it might give you some hints.

`CONFIG_ASYNC_TCP_RUNNING_CORE` - CPU core thread affinity that runs the queue events handling and executes server callbacks. Default is ANY core, so it means that for dualcore SoCs both cores could handle server activities. If your server's code is too heavy and unoptimized or you see that sometimes
server might affect other network activities, you might consider to bind it to the same core that runs Arduino code (1) to minimize affect on radio part. Otherwise you can leave the default to let RTOS decide where to run the thread based on priority

`CONFIG_ASYNC_TCP_STACK_SIZE` - stack size for the thread that runs sever events and callbacks. Default is 16k that is a way too much waste for well-defined short async code or simple static file handling. You might want to cosider reducing it to 4-8k to same RAM usage. If you do not know what this is or not sure about your callback code demands - leave it as default, should be enough even for very hungry callbacks in most cases.

> [!NOTE]
> This relates to ESP32 only, ESP8266 uses different ESPAsyncTCP lib that does not has this build options
Most of the crashes are caused by improper configuration of the library for the project.
Here are some recommendations to avoid them.

I personally use the following configuration in my projects:

```c++
-D CONFIG_ASYNC_TCP_MAX_ACK_TIME=5000 // (keep default)
-D CONFIG_ASYNC_TCP_PRIORITY=10 // (keep default)
-D CONFIG_ASYNC_TCP_QUEUE_SIZE=64 // (keep default)
-D CONFIG_ASYNC_TCP_RUNNING_CORE=1 // force async_tcp task to be on same core as Arduino app (default is any core)
-D CONFIG_ASYNC_TCP_STACK_SIZE=4096 // reduce the stack size (default is 16K)
-D CONFIG_ASYNC_TCP_MAX_ACK_TIME=5000 // (keep default)
-D CONFIG_ASYNC_TCP_PRIORITY=10 // (keep default)
-D CONFIG_ASYNC_TCP_QUEUE_SIZE=64 // (keep default)
-D CONFIG_ASYNC_TCP_RUNNING_CORE=1 // force async_tcp task to be on same core as the app (default is core 0)
-D CONFIG_ASYNC_TCP_STACK_SIZE=4096 // reduce the stack size (default is 16K)
```

## `AsyncWebSocketMessageBuffer` and `makeBuffer()`

The fork from [yubox-node-org](https://github.com/yubox-node-org/ESPAsyncWebServer) introduces some breaking API changes compared to the original library, especially regarding the use of `std::shared_ptr<std::vector<uint8_t>>` for WebSocket.
The fork from `yubox-node-org` introduces some breaking API changes compared to the original library, especially regarding the use of `std::shared_ptr<std::vector<uint8_t>>` for WebSocket.

This fork is compatible with the original library from [me-no-dev](https://github.com/me-no-dev/ESPAsyncWebServer) regarding WebSocket, and wraps the optimizations done by `yubox-node-org` in the `AsyncWebSocketMessageBuffer` class.
This fork is compatible with the original library from `me-no-dev` regarding WebSocket, and wraps the optimizations done by `yubox-node-org` in the `AsyncWebSocketMessageBuffer` class.
So you have the choice of which API to use.

Here are examples for serializing a Json document in a websocket message buffer:
Expand Down Expand Up @@ -270,24 +253,24 @@ AsyncMiddlewareFunction complexAuth([](AsyncWebServerRequest* request, ArMiddlew
**Here are the list of available middlewares:**

- `AsyncMiddlewareFunction`: can convert a lambda function (`ArMiddlewareCallback`) to a middleware
- `AsyncAuthenticationMiddleware`: to handle basic/digest authentication globally or per handler
- `AsyncAuthorizationMiddleware`: to handle authorization globally or per handler
- `AsyncCorsMiddleware`: to handle CORS preflight request globally or per handler
- `AsyncHeaderFilterMiddleware`: to filter out headers from the request
- `AsyncHeaderFreeMiddleware`: to only keep some headers from the request, and remove the others
- `AuthenticationMiddleware`: to handle basic/digest authentication globally or per handler
- `AuthorizationMiddleware`: to handle authorization globally or per handler
- `CorsMiddleware`: to handle CORS preflight request globally or per handler
- `HeaderFilterMiddleware`: to filter out headers from the request
- `HeaderFreeMiddleware`: to only keep some headers from the request, and remove the others
- `LoggerMiddleware`: to log requests globally or per handler with the same pattern as curl. Will also record request processing time
- `AsyncRateLimitMiddleware`: to limit the number of requests on a windows of time globally or per handler
- `RateLimitMiddleware`: to limit the number of requests on a windows of time globally or per handler

## How to use authentication with AsyncAuthenticationMiddleware
## How to use authentication with AuthenticationMiddleware

Do not use the `setUsername()` and `setPassword()` methods on the hanlders anymore.
They are deprecated.
These methods were causing a copy of the username and password for each handler, which is not efficient.

Now, you can use the `AsyncAuthenticationMiddleware` to handle authentication globally or per handler.
Now, you can use the `AuthenticationMiddleware` to handle authentication globally or per handler.

```c++
AsyncAuthenticationMiddleware authMiddleware;
AuthenticationMiddleware authMiddleware;

// [...]

Expand All @@ -309,23 +292,14 @@ myHandler.addMiddleware(&authMiddleware); // add authentication to a specific ha

## Migration to Middleware to improve performance and memory usage

- `AsyncEventSource.authorizeConnect(...)` => do not use this method anymore: add a common `AsyncAuthorizationMiddleware` to the handler or server, and make sure to add it AFTER the `AsyncAuthenticationMiddleware` if you use authentication.
- `AsyncWebHandler.setAuthentication(...)` => do not use this method anymore: add a common `AsyncAuthenticationMiddleware` to the handler or server
- `AsyncEventSource.authorizeConnect(...)` => do not use this method anymore: add a common `AuthorizationMiddleware` to the handler or server, and make sure to add it AFTER the `AuthenticationMiddleware` if you use authentication.
- `AsyncWebHandler.setAuthentication(...)` => do not use this method anymore: add a common `AuthenticationMiddleware` to the handler or server
- `ArUploadHandlerFunction` and `ArBodyHandlerFunction` => these callbacks receiving body data and upload and not calling anymore the authentication code for performance reasons.
These callbacks can be called multiple times during request parsing, so this is up to the user to now call the `AsyncAuthenticationMiddleware.allowed(request)` if needed and ideally when the method is called for the first time.
These callbacks can be called multiple times during request parsing, so this is up to the user to now call the `AuthenticationMiddleware.allowed(request)` if needed and ideally when the method is called for the first time.
These callbacks are also not triggering the whole middleware chain since they are not part of the request processing workflow (they are not the final handler).


## Maintainers
This fork of ESPAsyncWebServer and dependend libs are maintained as an opensource project at best effort level.
- [Mathieu Carbou](https://github.com/mathieucarbou)
- [Emil Muratov](https://github.com/vortigont)

Thanks to all who contributed by providing PRs, testing and reporting issues.


## Original Documentation
<!-- no toc -->

- [Why should you care](#why-should-you-care)
- [Important things to remember](#important-things-to-remember)
- [Principles of operation](#principles-of-operation)
Expand Down
Loading

0 comments on commit 24c8af6

Please sign in to comment.