Aktualizace na verzi 3.2.4
This commit is contained in:
parent
d8ffb99455
commit
3ba4d9d10d
15
README.md
15
README.md
@ -1,11 +1,13 @@
|
||||
# ESPAsyncWebServer
|
||||
|
||||
[![License: LGPL 3.0](https://img.shields.io/badge/License-LGPL%203.0-yellow.svg)](https://opensource.org/license/lgpl-3-0/)
|
||||
[![Continuous Integration](https://github.com/mathieucarbou/ESPAsyncWebServer/actions/workflows/ci.yml/badge.svg)](https://github.com/mathieucarbou/ESPAsyncWebServer/actions/workflows/ci.yml)
|
||||
|
||||
[![Latest Release](https://img.shields.io/github/release/mathieucarbou/ESPAsyncWebServer.svg)](https://GitHub.com/mathieucarbou/ESPAsyncWebServer/releases/)
|
||||
[![PlatformIO Registry](https://badges.registry.platformio.org/packages/mathieucarbou/library/ESPAsyncWebServer.svg)](https://registry.platformio.org/libraries/mathieucarbou/ESPAsyncWebServer)
|
||||
|
||||
[![License: LGPL 3.0](https://img.shields.io/badge/License-LGPL%203.0-yellow.svg)](https://opensource.org/license/lgpl-3-0/)
|
||||
[![Contributor Covenant](https://img.shields.io/badge/Contributor%20Covenant-2.1-4baaaa.svg)](code_of_conduct.md)
|
||||
|
||||
[![Build](https://github.com/mathieucarbou/ESPAsyncWebServer/actions/workflows/ci.yml/badge.svg)](https://github.com/mathieucarbou/ESPAsyncWebServer/actions/workflows/ci.yml)
|
||||
[![GitHub latest commit](https://badgen.net/github/last-commit/mathieucarbou/ESPAsyncWebServer)](https://GitHub.com/mathieucarbou/ESPAsyncWebServer/commit/)
|
||||
[![Gitpod Ready-to-Code](https://img.shields.io/badge/Gitpod-Ready--to--Code-blue?logo=gitpod)](https://gitpod.io/#https://github.com/mathieucarbou/ESPAsyncWebServer)
|
||||
|
||||
Asynchronous HTTP and WebSocket Server Library for ESP32, ESP8266 and RP2040
|
||||
@ -18,12 +20,12 @@ This fork is based on [yubox-node-org/ESPAsyncWebServer](https://github.com/yubo
|
||||
**WARNING** The library name was changed from `ESP Async WebServer` to `ESPAsyncWebServer` as per the Arduino Lint recommendations.
|
||||
|
||||
```
|
||||
mathieucarbou/ESPAsyncWebServer @ 3.2.0
|
||||
mathieucarbou/ESPAsyncWebServer @ 3.2.4
|
||||
```
|
||||
|
||||
Dependency:
|
||||
|
||||
- **ESP32**: `mathieucarbou/AsyncTCP @ 3.2.4` (Arduino IDE: [https://github.com/mathieucarbou/AsyncTCP#v3.2.4](https://github.com/mathieucarbou/AsyncTCP/releases/tag/v3.2.0))
|
||||
- **ESP32**: `mathieucarbou/AsyncTCP @ 3.2.5` (Arduino IDE: [https://github.com/mathieucarbou/AsyncTCP#v3.2.5](https://github.com/mathieucarbou/AsyncTCP/releases))
|
||||
- **ESP8266**: `esphome/ESPAsyncTCP-esphome @ 2.0.0` (Arduino IDE: [https://github.com/mathieucarbou/esphome-ESPAsyncTCP#v2.0.0](https://github.com/mathieucarbou/esphome-ESPAsyncTCP/releases/tag/v2.0.0))
|
||||
- **RP2040**: `khoih-prog/AsyncTCP_RP2040W @ 1.2.0` (Arduino IDE: [https://github.com/khoih-prog/AsyncTCP_RP2040W#v1.2.0](https://github.com/khoih-prog/AsyncTCP_RP2040W/releases/tag/v1.2.0))
|
||||
|
||||
@ -40,10 +42,9 @@ Dependency:
|
||||
- [@mathieucarbou](https://github.com/mathieucarbou): Arduino 3 / ESP-IDF 5.1 compatibility
|
||||
- [@mathieucarbou](https://github.com/mathieucarbou): Arduino Json 7 compatibility and backward compatible with 6 and 6 (changes in `AsyncJson.h`). The API to use Json has not changed. These are only internal changes.
|
||||
- [@mathieucarbou](https://github.com/mathieucarbou): CI
|
||||
- [@mathieucarbou](https://github.com/mathieucarbou): Depends on `mathieucarbou/AsyncTCP @ 3.2.4`
|
||||
- [@mathieucarbou](https://github.com/mathieucarbou): Depends on `mathieucarbou/AsyncTCP @ 3.2.5`
|
||||
- [@mathieucarbou](https://github.com/mathieucarbou): Deployed in PlatformIO registry and Arduino IDE library manager
|
||||
- [@mathieucarbou](https://github.com/mathieucarbou): Firmware size optimization: remove mbedtls dependency (accounts for 33KB in firmware)
|
||||
- [@mathieucarbou](https://github.com/mathieucarbou): Made DEFAULT_MAX_SSE_CLIENTS customizable
|
||||
- [@mathieucarbou](https://github.com/mathieucarbou): Made DEFAULT_MAX_WS_CLIENTS customizable
|
||||
- [@mathieucarbou](https://github.com/mathieucarbou): MessagePack Support ([#62](https://github.com/mathieucarbou/ESPAsyncWebServer/pull/62))
|
||||
- [@mathieucarbou](https://github.com/mathieucarbou): Remove filename after inline in Content-Disposition header according to RFC2183
|
||||
|
@ -1,11 +1,13 @@
|
||||
# ESPAsyncWebServer
|
||||
|
||||
[![License: LGPL 3.0](https://img.shields.io/badge/License-LGPL%203.0-yellow.svg)](https://opensource.org/license/lgpl-3-0/)
|
||||
[![Continuous Integration](https://github.com/mathieucarbou/ESPAsyncWebServer/actions/workflows/ci.yml/badge.svg)](https://github.com/mathieucarbou/ESPAsyncWebServer/actions/workflows/ci.yml)
|
||||
|
||||
[![Latest Release](https://img.shields.io/github/release/mathieucarbou/ESPAsyncWebServer.svg)](https://GitHub.com/mathieucarbou/ESPAsyncWebServer/releases/)
|
||||
[![PlatformIO Registry](https://badges.registry.platformio.org/packages/mathieucarbou/library/ESPAsyncWebServer.svg)](https://registry.platformio.org/libraries/mathieucarbou/ESPAsyncWebServer)
|
||||
|
||||
[![License: LGPL 3.0](https://img.shields.io/badge/License-LGPL%203.0-yellow.svg)](https://opensource.org/license/lgpl-3-0/)
|
||||
[![Contributor Covenant](https://img.shields.io/badge/Contributor%20Covenant-2.1-4baaaa.svg)](code_of_conduct.md)
|
||||
|
||||
[![Build](https://github.com/mathieucarbou/ESPAsyncWebServer/actions/workflows/ci.yml/badge.svg)](https://github.com/mathieucarbou/ESPAsyncWebServer/actions/workflows/ci.yml)
|
||||
[![GitHub latest commit](https://badgen.net/github/last-commit/mathieucarbou/ESPAsyncWebServer)](https://GitHub.com/mathieucarbou/ESPAsyncWebServer/commit/)
|
||||
[![Gitpod Ready-to-Code](https://img.shields.io/badge/Gitpod-Ready--to--Code-blue?logo=gitpod)](https://gitpod.io/#https://github.com/mathieucarbou/ESPAsyncWebServer)
|
||||
|
||||
Asynchronous HTTP and WebSocket Server Library for ESP32, ESP8266 and RP2040
|
||||
@ -18,12 +20,12 @@ This fork is based on [yubox-node-org/ESPAsyncWebServer](https://github.com/yubo
|
||||
**WARNING** The library name was changed from `ESP Async WebServer` to `ESPAsyncWebServer` as per the Arduino Lint recommendations.
|
||||
|
||||
```
|
||||
mathieucarbou/ESPAsyncWebServer @ 3.2.0
|
||||
mathieucarbou/ESPAsyncWebServer @ 3.2.4
|
||||
```
|
||||
|
||||
Dependency:
|
||||
|
||||
- **ESP32**: `mathieucarbou/AsyncTCP @ 3.2.4` (Arduino IDE: [https://github.com/mathieucarbou/AsyncTCP#v3.2.4](https://github.com/mathieucarbou/AsyncTCP/releases/tag/v3.2.0))
|
||||
- **ESP32**: `mathieucarbou/AsyncTCP @ 3.2.5` (Arduino IDE: [https://github.com/mathieucarbou/AsyncTCP#v3.2.5](https://github.com/mathieucarbou/AsyncTCP/releases))
|
||||
- **ESP8266**: `esphome/ESPAsyncTCP-esphome @ 2.0.0` (Arduino IDE: [https://github.com/mathieucarbou/esphome-ESPAsyncTCP#v2.0.0](https://github.com/mathieucarbou/esphome-ESPAsyncTCP/releases/tag/v2.0.0))
|
||||
- **RP2040**: `khoih-prog/AsyncTCP_RP2040W @ 1.2.0` (Arduino IDE: [https://github.com/khoih-prog/AsyncTCP_RP2040W#v1.2.0](https://github.com/khoih-prog/AsyncTCP_RP2040W/releases/tag/v1.2.0))
|
||||
|
||||
@ -40,10 +42,9 @@ Dependency:
|
||||
- [@mathieucarbou](https://github.com/mathieucarbou): Arduino 3 / ESP-IDF 5.1 compatibility
|
||||
- [@mathieucarbou](https://github.com/mathieucarbou): Arduino Json 7 compatibility and backward compatible with 6 and 6 (changes in `AsyncJson.h`). The API to use Json has not changed. These are only internal changes.
|
||||
- [@mathieucarbou](https://github.com/mathieucarbou): CI
|
||||
- [@mathieucarbou](https://github.com/mathieucarbou): Depends on `mathieucarbou/AsyncTCP @ 3.2.4`
|
||||
- [@mathieucarbou](https://github.com/mathieucarbou): Depends on `mathieucarbou/AsyncTCP @ 3.2.5`
|
||||
- [@mathieucarbou](https://github.com/mathieucarbou): Deployed in PlatformIO registry and Arduino IDE library manager
|
||||
- [@mathieucarbou](https://github.com/mathieucarbou): Firmware size optimization: remove mbedtls dependency (accounts for 33KB in firmware)
|
||||
- [@mathieucarbou](https://github.com/mathieucarbou): Made DEFAULT_MAX_SSE_CLIENTS customizable
|
||||
- [@mathieucarbou](https://github.com/mathieucarbou): Made DEFAULT_MAX_WS_CLIENTS customizable
|
||||
- [@mathieucarbou](https://github.com/mathieucarbou): MessagePack Support ([#62](https://github.com/mathieucarbou/ESPAsyncWebServer/pull/62))
|
||||
- [@mathieucarbou](https://github.com/mathieucarbou): Remove filename after inline in Content-Disposition header according to RFC2183
|
||||
|
@ -25,8 +25,40 @@
|
||||
#include <LittleFS.h>
|
||||
|
||||
AsyncWebServer server(80);
|
||||
AsyncEventSource events("/events");
|
||||
AsyncWebSocket ws("/ws");
|
||||
|
||||
const char* PARAM_MESSAGE = "message";
|
||||
const char* PARAM_MESSAGE PROGMEM = "message";
|
||||
const char* SSE_HTLM PROGMEM = R"(
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Server-Sent Events</title>
|
||||
<script>
|
||||
if (!!window.EventSource) {
|
||||
var source = new EventSource('/events');
|
||||
source.addEventListener('open', function(e) {
|
||||
console.log("Events Connected");
|
||||
}, false);
|
||||
source.addEventListener('error', function(e) {
|
||||
if (e.target.readyState != EventSource.OPEN) {
|
||||
console.log("Events Disconnected");
|
||||
}
|
||||
}, false);
|
||||
source.addEventListener('message', function(e) {
|
||||
console.log("message", e.data);
|
||||
}, false);
|
||||
source.addEventListener('heartbeat', function(e) {
|
||||
console.log("heartbeat", e.data);
|
||||
}, false);
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Open your browser console!</h1>
|
||||
</body>
|
||||
</html>
|
||||
)";
|
||||
|
||||
void notFound(AsyncWebServerRequest* request) {
|
||||
request->send(404, "text/plain", "Not found");
|
||||
@ -73,8 +105,11 @@ void setup() {
|
||||
server.on("/download", HTTP_HEAD | HTTP_GET, [](AsyncWebServerRequest* request) {
|
||||
if (request->method() == HTTP_HEAD) {
|
||||
AsyncWebServerResponse* response = request->beginResponse(200, "application/octet-stream");
|
||||
response->setContentLength(1024); // myFile.getSize()
|
||||
response->addHeader("Accept-Ranges", "bytes");
|
||||
response->addHeader(asyncsrv::T_Accept_Ranges, "bytes");
|
||||
response->addHeader(asyncsrv::T_Content_Length, 10);
|
||||
response->setContentLength(1024); // overrides previous one
|
||||
response->addHeader(asyncsrv::T_Content_Type, "foo");
|
||||
response->setContentType("application/octet-stream"); // overrides previous one
|
||||
// ...
|
||||
request->send(response);
|
||||
} else {
|
||||
@ -108,7 +143,7 @@ void setup() {
|
||||
|
||||
// receives JSON and sends JSON
|
||||
jsonHandler->onRequest([](AsyncWebServerRequest* request, JsonVariant& json) {
|
||||
JsonObject jsonObj = json.as<JsonObject>();
|
||||
// JsonObject jsonObj = json.as<JsonObject>();
|
||||
// ...
|
||||
|
||||
AsyncJsonResponse* response = new AsyncJsonResponse();
|
||||
@ -131,7 +166,7 @@ void setup() {
|
||||
|
||||
// receives MessagePack and sends MessagePack
|
||||
msgPackHandler->onRequest([](AsyncWebServerRequest* request, JsonVariant& json) {
|
||||
JsonObject jsonObj = json.as<JsonObject>();
|
||||
// JsonObject jsonObj = json.as<JsonObject>();
|
||||
// ...
|
||||
|
||||
AsyncMessagePackResponse* response = new AsyncMessagePackResponse();
|
||||
@ -150,6 +185,43 @@ void setup() {
|
||||
request->send(response);
|
||||
});
|
||||
|
||||
events.onConnect([](AsyncEventSourceClient* client) {
|
||||
if (client->lastId()) {
|
||||
Serial.printf("SSE Client reconnected! Last message ID that it gat is: %" PRIu32 "\n", client->lastId());
|
||||
}
|
||||
client->send("hello!", NULL, millis(), 1000);
|
||||
});
|
||||
|
||||
server.on("/sse", HTTP_GET, [](AsyncWebServerRequest* request) {
|
||||
request->send(200, "text/html", SSE_HTLM);
|
||||
});
|
||||
|
||||
ws.onEvent([](AsyncWebSocket* server, AsyncWebSocketClient* client, AwsEventType type, void* arg, uint8_t* data, size_t len) {
|
||||
(void) len;
|
||||
if (type == WS_EVT_CONNECT) {
|
||||
Serial.println("ws connect");
|
||||
client->setCloseClientOnQueueFull(false);
|
||||
client->ping();
|
||||
} else if (type == WS_EVT_DISCONNECT) {
|
||||
Serial.println("ws disconnect");
|
||||
} else if (type == WS_EVT_ERROR) {
|
||||
Serial.println("ws error");
|
||||
} else if (type == WS_EVT_PONG) {
|
||||
Serial.println("ws pong");
|
||||
} else if (type == WS_EVT_DATA) {
|
||||
AwsFrameInfo* info = (AwsFrameInfo*)arg;
|
||||
String msg = "";
|
||||
if (info->final && info->index == 0 && info->len == len) {
|
||||
if (info->opcode == WS_TEXT) {
|
||||
data[len] = 0;
|
||||
Serial.printf("ws text: %s\n", (char*)data);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
server.addHandler(&events);
|
||||
server.addHandler(&ws);
|
||||
server.addHandler(jsonHandler);
|
||||
server.addHandler(msgPackHandler);
|
||||
|
||||
@ -158,5 +230,20 @@ void setup() {
|
||||
server.begin();
|
||||
}
|
||||
|
||||
uint32_t lastSSE = 0;
|
||||
uint32_t deltaSSE = 5;
|
||||
|
||||
uint32_t lastWS = 0;
|
||||
uint32_t deltaWS = 100;
|
||||
|
||||
void loop() {
|
||||
uint32_t now = millis();
|
||||
if (now - lastSSE >= deltaSSE) {
|
||||
events.send(String("ping-") + now, "heartbeat", now);
|
||||
lastSSE = millis();
|
||||
}
|
||||
if (now - lastWS >= deltaWS) {
|
||||
ws.printfAll("kp%.4f", (10.0 / 3.0));
|
||||
lastWS = millis();
|
||||
}
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "ESPAsyncWebServer",
|
||||
"version": "3.2.0",
|
||||
"version": "3.2.4",
|
||||
"description": "Asynchronous HTTP and WebSocket Server Library for ESP32, ESP8266 and RP2040. Supports: WebSocket, SSE, Authentication, Arduino Json 7, File Upload, Static File serving, URL Rewrite, URL Redirect, etc.",
|
||||
"keywords": "http,async,websocket,webserver",
|
||||
"homepage": "https://github.com/mathieucarbou/ESPAsyncWebServer",
|
||||
@ -28,7 +28,7 @@
|
||||
{
|
||||
"owner": "mathieucarbou",
|
||||
"name": "AsyncTCP",
|
||||
"version": "^3.2.4",
|
||||
"version": "^3.2.5",
|
||||
"platforms": "espressif32"
|
||||
},
|
||||
{
|
||||
|
@ -1,5 +1,5 @@
|
||||
name=ESPAsyncWebServer
|
||||
version=3.2.0
|
||||
version=3.2.4
|
||||
author=Me-No-Dev
|
||||
maintainer=Mathieu Carbou <mathieu.carbou@gmail.com>
|
||||
sentence=Asynchronous HTTP and WebSocket Server Library for ESP32, ESP8266 and RP2040
|
||||
|
@ -2,6 +2,7 @@
|
||||
framework = arduino
|
||||
build_flags =
|
||||
-Wall -Wextra
|
||||
-Wno-unused-parameter
|
||||
-D CONFIG_ARDUHAL_LOG_COLORS
|
||||
-D CORE_DEBUG_LEVEL=ARDUHAL_LOG_LEVEL_VERBOSE
|
||||
-D CONFIG_ASYNC_TCP_MAX_ACK_TIME=3000
|
||||
@ -22,19 +23,12 @@ src_dir = examples/SimpleServer
|
||||
; src_dir = examples/Draft
|
||||
; src_dir = examples/issues/Issue14
|
||||
|
||||
[env:arduino]
|
||||
platform = espressif32
|
||||
board = esp32dev
|
||||
lib_deps =
|
||||
bblanchon/ArduinoJson @ 7.1.0
|
||||
mathieucarbou/AsyncTCP @ 3.2.4
|
||||
|
||||
[env:arduino-2]
|
||||
platform = espressif32@6.8.1
|
||||
board = esp32dev
|
||||
lib_deps =
|
||||
bblanchon/ArduinoJson @ 7.1.0
|
||||
mathieucarbou/AsyncTCP @ 3.2.4
|
||||
mathieucarbou/AsyncTCP @ 3.2.5
|
||||
|
||||
[env:arduino-3]
|
||||
platform = espressif32
|
||||
@ -44,7 +38,7 @@ platform_packages=
|
||||
board = esp32dev
|
||||
lib_deps =
|
||||
bblanchon/ArduinoJson @ 7.1.0
|
||||
mathieucarbou/AsyncTCP @ 3.2.4
|
||||
mathieucarbou/AsyncTCP @ 3.2.5
|
||||
|
||||
[env:esp8266]
|
||||
platform = espressif8266
|
||||
@ -70,18 +64,18 @@ platform = https://github.com/pioarduino/platform-espressif32/releases/download/
|
||||
board = esp32dev
|
||||
lib_deps =
|
||||
bblanchon/ArduinoJson @ 7.1.0
|
||||
mathieucarbou/AsyncTCP @ 3.2.4
|
||||
mathieucarbou/AsyncTCP @ 3.2.5
|
||||
|
||||
[env:pioarduino-c6]
|
||||
platform = https://github.com/pioarduino/platform-espressif32/releases/download/51.03.04/platform-espressif32.zip
|
||||
board = esp32-c6-devkitc-1
|
||||
lib_deps =
|
||||
bblanchon/ArduinoJson @ 7.1.0
|
||||
mathieucarbou/AsyncTCP @ 3.2.4
|
||||
mathieucarbou/AsyncTCP @ 3.2.5
|
||||
|
||||
[env:pioarduino-h2]
|
||||
platform = https://github.com/pioarduino/platform-espressif32/releases/download/51.03.04/platform-espressif32.zip
|
||||
board = esp32-h2-devkitm-1
|
||||
lib_deps =
|
||||
bblanchon/ArduinoJson @ 7.1.0
|
||||
mathieucarbou/AsyncTCP @ 3.2.4
|
||||
mathieucarbou/AsyncTCP @ 3.2.5
|
||||
|
@ -128,8 +128,7 @@ AsyncEventSourceMessage::~AsyncEventSourceMessage() {
|
||||
free(_data);
|
||||
}
|
||||
|
||||
size_t AsyncEventSourceMessage::ack(size_t len, uint32_t time) {
|
||||
(void)time;
|
||||
size_t AsyncEventSourceMessage::ack(size_t len, __attribute__((unused)) uint32_t time) {
|
||||
// If the whole message is now acked...
|
||||
if (_acked + len > _len) {
|
||||
// Return the number of extra bytes acked (they will be carried on to the next message)
|
||||
@ -142,17 +141,19 @@ size_t AsyncEventSourceMessage::ack(size_t len, uint32_t time) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// This could also return void as the return value is not used.
|
||||
// Leaving as-is for compatibility...
|
||||
size_t AsyncEventSourceMessage::send(AsyncClient* client) {
|
||||
if (_sent >= _len) {
|
||||
size_t AsyncEventSourceMessage::write(AsyncClient* client) {
|
||||
if (_sent >= _len || !client->canSend()) {
|
||||
return 0;
|
||||
}
|
||||
const size_t len_to_send = _len - _sent;
|
||||
auto position = reinterpret_cast<const char*>(_data + _sent);
|
||||
const size_t sent_now = client->write(position, len_to_send);
|
||||
_sent += sent_now;
|
||||
return sent_now;
|
||||
size_t len = min(_len - _sent, client->space());
|
||||
size_t sent = client->add((const char*)_data + _sent, len);
|
||||
_sent += sent;
|
||||
return sent;
|
||||
}
|
||||
|
||||
size_t AsyncEventSourceMessage::send(AsyncClient* client) {
|
||||
size_t sent = write(client);
|
||||
return sent && client->send() ? sent : 0;
|
||||
}
|
||||
|
||||
// Client
|
||||
@ -174,6 +175,8 @@ AsyncEventSourceClient::AsyncEventSourceClient(AsyncWebServerRequest* request, A
|
||||
|
||||
_server->_addClient(this);
|
||||
delete request;
|
||||
|
||||
_client->setNoDelay(true);
|
||||
}
|
||||
|
||||
AsyncEventSourceClient::~AsyncEventSourceClient() {
|
||||
@ -211,11 +214,6 @@ void AsyncEventSourceClient::_onAck(size_t len, uint32_t time) {
|
||||
// Same here, acquiring the lock early
|
||||
std::lock_guard<std::mutex> lock(_lockmq);
|
||||
#endif
|
||||
while (len && _messageQueue.size()) {
|
||||
len = _messageQueue.front().ack(len, time);
|
||||
if (_messageQueue.front().finished())
|
||||
_messageQueue.pop_front();
|
||||
}
|
||||
_runQueue();
|
||||
}
|
||||
|
||||
@ -264,11 +262,24 @@ size_t AsyncEventSourceClient::packetsWaiting() const {
|
||||
}
|
||||
|
||||
void AsyncEventSourceClient::_runQueue() {
|
||||
// Calls to this private method now already protected by _lockmq acquisition
|
||||
// so no extra call of _lockmq.lock() here..
|
||||
for (auto& i : _messageQueue) {
|
||||
if (!i.sent())
|
||||
i.send(_client);
|
||||
size_t total_bytes_written = 0;
|
||||
for (auto i = _messageQueue.begin(); i != _messageQueue.end(); ++i) {
|
||||
if (!i->sent()) {
|
||||
const size_t bytes_written = i->write(_client);
|
||||
total_bytes_written += bytes_written;
|
||||
if (bytes_written == 0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (total_bytes_written > 0)
|
||||
_client->send();
|
||||
|
||||
size_t len = total_bytes_written;
|
||||
while (len && _messageQueue.size()) {
|
||||
len = _messageQueue.front().ack(len);
|
||||
if (_messageQueue.front().finished()) {
|
||||
_messageQueue.pop_front();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -392,7 +403,8 @@ AsyncEventSourceResponse::AsyncEventSourceResponse(AsyncEventSource* server) {
|
||||
}
|
||||
|
||||
void AsyncEventSourceResponse::_respond(AsyncWebServerRequest* request) {
|
||||
String out = _assembleHead(request->version());
|
||||
String out;
|
||||
_assembleHead(out, request->version());
|
||||
request->client()->write(out.c_str(), _headLength);
|
||||
_state = RESPONSE_WAIT_ACK;
|
||||
}
|
||||
|
@ -49,14 +49,6 @@
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef DEFAULT_MAX_SSE_CLIENTS
|
||||
#ifdef ESP32
|
||||
#define DEFAULT_MAX_SSE_CLIENTS 8
|
||||
#else
|
||||
#define DEFAULT_MAX_SSE_CLIENTS 4
|
||||
#endif
|
||||
#endif
|
||||
|
||||
class AsyncEventSource;
|
||||
class AsyncEventSourceResponse;
|
||||
class AsyncEventSourceClient;
|
||||
@ -74,7 +66,8 @@ class AsyncEventSourceMessage {
|
||||
public:
|
||||
AsyncEventSourceMessage(const char* data, size_t len);
|
||||
~AsyncEventSourceMessage();
|
||||
size_t ack(size_t len, uint32_t time __attribute__((unused)));
|
||||
size_t ack(size_t len, uint32_t time = 0);
|
||||
size_t write(AsyncClient* client);
|
||||
size_t send(AsyncClient* client);
|
||||
bool finished() { return _acked == _len; }
|
||||
bool sent() { return _sent == _len; }
|
||||
@ -99,6 +92,8 @@ class AsyncEventSourceClient {
|
||||
AsyncClient* client() { return _client; }
|
||||
void close();
|
||||
void write(const char* message, size_t len);
|
||||
void send(const String& message, const String& event, uint32_t id = 0, uint32_t reconnect = 0) { send(message.c_str(), event.c_str(), id, reconnect); }
|
||||
void send(const String& message, const char* event, uint32_t id = 0, uint32_t reconnect = 0) { send(message.c_str(), event, id, reconnect); }
|
||||
void send(const char* message, const char* event = NULL, uint32_t id = 0, uint32_t reconnect = 0);
|
||||
bool connected() const { return (_client != NULL) && _client->connected(); }
|
||||
uint32_t lastId() const { return _lastId; }
|
||||
@ -131,6 +126,8 @@ class AsyncEventSource : public AsyncWebHandler {
|
||||
void close();
|
||||
void onConnect(ArEventHandlerFunction cb);
|
||||
void authorizeConnect(ArAuthorizeConnectHandler cb);
|
||||
void send(const String& message, const String& event, uint32_t id = 0, uint32_t reconnect = 0) { send(message.c_str(), event.c_str(), id, reconnect); }
|
||||
void send(const String& message, const char* event, uint32_t id = 0, uint32_t reconnect = 0) { send(message.c_str(), event, id, reconnect); }
|
||||
void send(const char* message, const char* event = NULL, uint32_t id = 0, uint32_t reconnect = 0);
|
||||
// number of clients connected
|
||||
size_t count() const;
|
||||
|
@ -27,7 +27,7 @@
|
||||
|
||||
#if defined(ESP32)
|
||||
#if ESP_IDF_VERSION_MAJOR < 5
|
||||
#include "./port/SHA1Builder.h"
|
||||
#include "BackPort_SHA1Builder.h"
|
||||
#else
|
||||
#include <SHA1Builder.h>
|
||||
#endif
|
||||
@ -36,11 +36,8 @@
|
||||
#include <Hash.h>
|
||||
#endif
|
||||
|
||||
#define MAX_PRINTF_LEN 64
|
||||
|
||||
using namespace asyncsrv;
|
||||
|
||||
|
||||
size_t webSocketSendFrameWindow(AsyncClient* client) {
|
||||
if (!client->canSend())
|
||||
return 0;
|
||||
@ -589,30 +586,23 @@ void AsyncWebSocketClient::_onData(void* pbuf, size_t plen) {
|
||||
size_t AsyncWebSocketClient::printf(const char* format, ...) {
|
||||
va_list arg;
|
||||
va_start(arg, format);
|
||||
char* temp = new char[MAX_PRINTF_LEN];
|
||||
if (!temp) {
|
||||
va_end(arg);
|
||||
return 0;
|
||||
}
|
||||
char* buffer = temp;
|
||||
size_t len = vsnprintf(temp, MAX_PRINTF_LEN, format, arg);
|
||||
size_t len = vsnprintf(nullptr, 0, format, arg);
|
||||
va_end(arg);
|
||||
|
||||
if (len > (MAX_PRINTF_LEN - 1)) {
|
||||
buffer = new char[len + 1];
|
||||
if (!buffer) {
|
||||
delete[] temp;
|
||||
if (len == 0)
|
||||
return 0;
|
||||
}
|
||||
|
||||
char* buffer = new char[len + 1];
|
||||
|
||||
if (!buffer)
|
||||
return 0;
|
||||
|
||||
va_start(arg, format);
|
||||
vsnprintf(buffer, len + 1, format, arg);
|
||||
len = vsnprintf(buffer, len + 1, format, arg);
|
||||
va_end(arg);
|
||||
}
|
||||
|
||||
text(buffer, len);
|
||||
if (buffer != temp) {
|
||||
delete[] buffer;
|
||||
}
|
||||
delete[] temp;
|
||||
return len;
|
||||
}
|
||||
|
||||
@ -620,30 +610,23 @@ size_t AsyncWebSocketClient::printf(const char* format, ...) {
|
||||
size_t AsyncWebSocketClient::printf_P(PGM_P formatP, ...) {
|
||||
va_list arg;
|
||||
va_start(arg, formatP);
|
||||
char* temp = new char[MAX_PRINTF_LEN];
|
||||
if (!temp) {
|
||||
va_end(arg);
|
||||
return 0;
|
||||
}
|
||||
char* buffer = temp;
|
||||
size_t len = vsnprintf_P(temp, MAX_PRINTF_LEN, formatP, arg);
|
||||
size_t len = vsnprintf_P(nullptr, 0, formatP, arg);
|
||||
va_end(arg);
|
||||
|
||||
if (len > (MAX_PRINTF_LEN - 1)) {
|
||||
buffer = new char[len + 1];
|
||||
if (!buffer) {
|
||||
delete[] temp;
|
||||
if (len == 0)
|
||||
return 0;
|
||||
}
|
||||
|
||||
char* buffer = new char[len + 1];
|
||||
|
||||
if (!buffer)
|
||||
return 0;
|
||||
|
||||
va_start(arg, formatP);
|
||||
vsnprintf_P(buffer, len + 1, formatP, arg);
|
||||
len = vsnprintf_P(buffer, len + 1, formatP, arg);
|
||||
va_end(arg);
|
||||
}
|
||||
|
||||
text(buffer, len);
|
||||
if (buffer != temp) {
|
||||
delete[] buffer;
|
||||
}
|
||||
delete[] temp;
|
||||
return len;
|
||||
}
|
||||
#endif
|
||||
@ -1008,22 +991,24 @@ size_t AsyncWebSocket::printf(uint32_t id, const char* format, ...) {
|
||||
|
||||
size_t AsyncWebSocket::printfAll(const char* format, ...) {
|
||||
va_list arg;
|
||||
char* temp = new char[MAX_PRINTF_LEN];
|
||||
if (!temp)
|
||||
va_start(arg, format);
|
||||
size_t len = vsnprintf(nullptr, 0, format, arg);
|
||||
va_end(arg);
|
||||
|
||||
if (len == 0)
|
||||
return 0;
|
||||
|
||||
char* buffer = new char[len + 1];
|
||||
|
||||
if (!buffer)
|
||||
return 0;
|
||||
|
||||
va_start(arg, format);
|
||||
size_t len = vsnprintf(temp, MAX_PRINTF_LEN, format, arg);
|
||||
va_end(arg);
|
||||
delete[] temp;
|
||||
|
||||
AsyncWebSocketSharedBuffer buffer = std::make_shared<std::vector<uint8_t>>(len);
|
||||
|
||||
va_start(arg, format);
|
||||
vsnprintf((char*)buffer->data(), len + 1, format, arg);
|
||||
len = vsnprintf(buffer, len + 1, format, arg);
|
||||
va_end(arg);
|
||||
|
||||
textAll(buffer);
|
||||
textAll(buffer, len);
|
||||
delete[] buffer;
|
||||
return len;
|
||||
}
|
||||
|
||||
@ -1042,22 +1027,24 @@ size_t AsyncWebSocket::printf_P(uint32_t id, PGM_P formatP, ...) {
|
||||
|
||||
size_t AsyncWebSocket::printfAll_P(PGM_P formatP, ...) {
|
||||
va_list arg;
|
||||
char* temp = new char[MAX_PRINTF_LEN];
|
||||
if (!temp)
|
||||
va_start(arg, formatP);
|
||||
size_t len = vsnprintf_P(nullptr, 0, formatP, arg);
|
||||
va_end(arg);
|
||||
|
||||
if (len == 0)
|
||||
return 0;
|
||||
|
||||
char* buffer = new char[len + 1];
|
||||
|
||||
if (!buffer)
|
||||
return 0;
|
||||
|
||||
va_start(arg, formatP);
|
||||
size_t len = vsnprintf_P(temp, MAX_PRINTF_LEN, formatP, arg);
|
||||
va_end(arg);
|
||||
delete[] temp;
|
||||
|
||||
AsyncWebSocketSharedBuffer buffer = std::make_shared<std::vector<uint8_t>>(len + 1);
|
||||
|
||||
va_start(arg, formatP);
|
||||
vsnprintf_P((char*)buffer->data(), len + 1, formatP, arg);
|
||||
len = vsnprintf_P(buffer, len + 1, formatP, arg);
|
||||
va_end(arg);
|
||||
|
||||
textAll(buffer);
|
||||
textAll(buffer, len);
|
||||
delete[] buffer;
|
||||
return len;
|
||||
}
|
||||
#endif
|
||||
@ -1192,7 +1179,8 @@ void AsyncWebSocketResponse::_respond(AsyncWebServerRequest* request) {
|
||||
request->client()->close(true);
|
||||
return;
|
||||
}
|
||||
String out(_assembleHead(request->version()));
|
||||
String out;
|
||||
_assembleHead(out, request->version());
|
||||
request->client()->write(out.c_str(), _headLength);
|
||||
_state = RESPONSE_WAIT_ACK;
|
||||
}
|
||||
|
@ -23,7 +23,7 @@
|
||||
#include <Arduino.h>
|
||||
#if ESP_IDF_VERSION_MAJOR < 5
|
||||
|
||||
#include "SHA1Builder.h"
|
||||
#include "BackPort_SHA1Builder.h"
|
||||
|
||||
// 32-bit integer manipulation macros (big endian)
|
||||
|
||||
@ -202,7 +202,7 @@ void SHA1Builder::process(const uint8_t *data) {
|
||||
|
||||
// Public methods
|
||||
|
||||
void SHA1Builder::begin(void) {
|
||||
void SHA1Builder::begin() {
|
||||
total[0] = 0;
|
||||
total[1] = 0;
|
||||
|
@ -12,6 +12,9 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include <Arduino.h>
|
||||
#if ESP_IDF_VERSION_MAJOR < 5
|
||||
|
||||
#ifndef SHA1Builder_h
|
||||
#define SHA1Builder_h
|
||||
|
||||
@ -37,3 +40,5 @@ class SHA1Builder {
|
||||
};
|
||||
|
||||
#endif // SHA1Builder_h
|
||||
|
||||
#endif // ESP_IDF_VERSION_MAJOR < 5
|
@ -45,10 +45,10 @@
|
||||
|
||||
#include "literals.h"
|
||||
|
||||
#define ASYNCWEBSERVER_VERSION "3.2.0"
|
||||
#define ASYNCWEBSERVER_VERSION "3.2.4"
|
||||
#define ASYNCWEBSERVER_VERSION_MAJOR 3
|
||||
#define ASYNCWEBSERVER_VERSION_MINOR 2
|
||||
#define ASYNCWEBSERVER_VERSION_REVISION 0
|
||||
#define ASYNCWEBSERVER_VERSION_REVISION 4
|
||||
#define ASYNCWEBSERVER_FORK_mathieucarbou
|
||||
|
||||
#ifdef ASYNCWEBSERVER_REGEX
|
||||
@ -155,7 +155,9 @@ class AsyncWebHeader {
|
||||
const String& name() const { return _name; }
|
||||
const String& value() const { return _value; }
|
||||
String toString() const {
|
||||
String str = _name;
|
||||
String str;
|
||||
str.reserve(_name.length() + _value.length() + 2);
|
||||
str.concat(_name);
|
||||
str.concat((char)0x3a);
|
||||
str.concat((char)0x20);
|
||||
str.concat(_value);
|
||||
@ -333,11 +335,15 @@ class AsyncWebServerRequest {
|
||||
void sendChunked(const char* contentType, AwsResponseFiller callback, AwsTemplateProcessor templateCallback = nullptr) { send(beginChunkedResponse(contentType, callback, templateCallback)); }
|
||||
void sendChunked(const String& contentType, AwsResponseFiller callback, AwsTemplateProcessor templateCallback = nullptr) { send(beginChunkedResponse(contentType, callback, templateCallback)); }
|
||||
|
||||
#ifndef ESP8266
|
||||
[[deprecated("Replaced by send(...)")]]
|
||||
#endif
|
||||
void send_P(int code, const String& contentType, const uint8_t* content, size_t len, AwsTemplateProcessor callback = nullptr) {
|
||||
send(code, contentType, content, len, callback);
|
||||
}
|
||||
#ifndef ESP8266
|
||||
[[deprecated("Replaced by send(...)")]]
|
||||
#endif
|
||||
void send_P(int code, const String& contentType, PGM_P content, AwsTemplateProcessor callback = nullptr) {
|
||||
send(code, contentType, content, callback);
|
||||
}
|
||||
@ -370,13 +376,17 @@ class AsyncWebServerRequest {
|
||||
AsyncResponseStream* beginResponseStream(const char* contentType, size_t bufferSize = 1460);
|
||||
AsyncResponseStream* beginResponseStream(const String& contentType, size_t bufferSize = 1460) { return beginResponseStream(contentType.c_str(), bufferSize); }
|
||||
|
||||
#ifndef ESP8266
|
||||
[[deprecated("Replaced by beginResponse(...)")]]
|
||||
#endif
|
||||
AsyncWebServerResponse* beginResponse_P(int code, const String& contentType, const uint8_t* content, size_t len, AwsTemplateProcessor callback = nullptr) {
|
||||
return beginResponse(code, contentType, content, len, callback);
|
||||
return beginResponse(code, contentType.c_str(), content, len, callback);
|
||||
}
|
||||
#ifndef ESP8266
|
||||
[[deprecated("Replaced by beginResponse(...)")]]
|
||||
#endif
|
||||
AsyncWebServerResponse* beginResponse_P(int code, const String& contentType, PGM_P content, AwsTemplateProcessor callback = nullptr) {
|
||||
return beginResponse(code, contentType, content, callback);
|
||||
return beginResponse(code, contentType.c_str(), content, callback);
|
||||
}
|
||||
|
||||
#ifdef ESP8266
|
||||
@ -583,8 +593,21 @@ class AsyncWebServerResponse {
|
||||
virtual void setContentType(const char* type);
|
||||
virtual bool addHeader(const char* name, const char* value, bool replaceExisting = true);
|
||||
bool addHeader(const String& name, const String& value, bool replaceExisting = true) { return addHeader(name.c_str(), value.c_str(), replaceExisting); }
|
||||
bool addHeader(const char* name, long value, bool replaceExisting = true) { return addHeader(name, String(value), replaceExisting); }
|
||||
bool addHeader(const String& name, long value, bool replaceExisting = true) { return addHeader(name.c_str(), value, replaceExisting); }
|
||||
virtual bool removeHeader(const char* name);
|
||||
virtual String _assembleHead(uint8_t version);
|
||||
virtual const AsyncWebHeader* getHeader(const char* name) const;
|
||||
|
||||
#ifndef ESP8266
|
||||
[[deprecated("Use instead: _assembleHead(String& buffer, uint8_t version)")]]
|
||||
#endif
|
||||
String _assembleHead(uint8_t version) {
|
||||
String buffer;
|
||||
_assembleHead(buffer, version);
|
||||
return buffer;
|
||||
}
|
||||
virtual void _assembleHead(String& buffer, uint8_t version);
|
||||
|
||||
virtual bool _started() const;
|
||||
virtual bool _finished() const;
|
||||
virtual bool _failed() const;
|
||||
|
@ -624,7 +624,6 @@ bool AsyncWebServerRequest::hasHeader(const __FlashStringHelper* data) const {
|
||||
|
||||
const AsyncWebHeader* AsyncWebServerRequest::getHeader(const char* name) const {
|
||||
auto iter = std::find_if(std::begin(_headers), std::end(_headers), [&name](const AsyncWebHeader& header) { return header.name().equalsIgnoreCase(name); });
|
||||
|
||||
return (iter == std::end(_headers)) ? nullptr : &(*iter);
|
||||
}
|
||||
|
||||
|
@ -126,8 +126,7 @@ const char* AsyncWebServerResponse::responseCodeToString(int code) {
|
||||
}
|
||||
}
|
||||
#else // ESP8266
|
||||
const __FlashStringHelper* AsyncWebServerResponse::responseCodeToString(int code)
|
||||
{
|
||||
const __FlashStringHelper* AsyncWebServerResponse::responseCodeToString(int code) {
|
||||
switch (code) {
|
||||
case 100:
|
||||
return FPSTR(T_HTTP_CODE_100);
|
||||
@ -230,12 +229,12 @@ void AsyncWebServerResponse::setCode(int code) {
|
||||
}
|
||||
|
||||
void AsyncWebServerResponse::setContentLength(size_t len) {
|
||||
if (_state == RESPONSE_SETUP)
|
||||
if (_state == RESPONSE_SETUP && addHeader(T_Content_Length, len, true))
|
||||
_contentLength = len;
|
||||
}
|
||||
|
||||
void AsyncWebServerResponse::setContentType(const char* type) {
|
||||
if (_state == RESPONSE_SETUP)
|
||||
if (_state == RESPONSE_SETUP && addHeader(T_Content_Type, type, true))
|
||||
_contentType = type;
|
||||
}
|
||||
|
||||
@ -249,6 +248,11 @@ bool AsyncWebServerResponse::removeHeader(const char* name) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const AsyncWebHeader* AsyncWebServerResponse::getHeader(const char* name) const {
|
||||
auto iter = std::find_if(std::begin(_headers), std::end(_headers), [&name](const AsyncWebHeader& header) { return header.name().equalsIgnoreCase(name); });
|
||||
return (iter == std::end(_headers)) ? nullptr : &(*iter);
|
||||
}
|
||||
|
||||
bool AsyncWebServerResponse::addHeader(const char* name, const char* value, bool replaceExisting) {
|
||||
for (auto i = _headers.begin(); i != _headers.end(); ++i) {
|
||||
if (i->name().equalsIgnoreCase(name)) {
|
||||
@ -268,41 +272,56 @@ bool AsyncWebServerResponse::addHeader(const char* name, const char* value, bool
|
||||
return true;
|
||||
}
|
||||
|
||||
String AsyncWebServerResponse::_assembleHead(uint8_t version) {
|
||||
void AsyncWebServerResponse::_assembleHead(String& buffer, uint8_t version) {
|
||||
if (version) {
|
||||
addHeader(T_Accept_Ranges, T_none, false);
|
||||
if (_chunked)
|
||||
addHeader(T_Transfer_Encoding, T_chunked, false);
|
||||
}
|
||||
String out;
|
||||
constexpr size_t bufSize = 300;
|
||||
char buf[bufSize];
|
||||
|
||||
#ifndef ESP8266
|
||||
snprintf(buf, bufSize, "HTTP/1.%d %d %s\r\n", version, _code, responseCodeToString(_code));
|
||||
if (_sendContentLength)
|
||||
addHeader(T_Content_Length, String(_contentLength), false);
|
||||
|
||||
if (_contentType.length())
|
||||
addHeader(T_Content_Type, _contentType.c_str(), false);
|
||||
|
||||
// precompute buffer size to avoid reallocations by String class
|
||||
size_t len = 0;
|
||||
len += 50; // HTTP/1.1 200 <reason>\r\n
|
||||
for (const auto& header : _headers)
|
||||
len += header.name().length() + header.value().length() + 4;
|
||||
|
||||
// prepare buffer
|
||||
buffer.reserve(len);
|
||||
|
||||
// HTTP header
|
||||
#ifdef ESP8266
|
||||
buffer.concat(PSTR("HTTP/1."));
|
||||
#else
|
||||
snprintf_P(buf, bufSize, PSTR("HTTP/1.%d %d %s\r\n"), version, _code, String(responseCodeToString(_code)).c_str());
|
||||
buffer.concat("HTTP/1.");
|
||||
#endif
|
||||
out.concat(buf);
|
||||
|
||||
if (_sendContentLength) {
|
||||
snprintf_P(buf, bufSize, PSTR("Content-Length: %d\r\n"), _contentLength);
|
||||
out.concat(buf);
|
||||
}
|
||||
if (_contentType.length()) {
|
||||
snprintf_P(buf, bufSize, PSTR("Content-Type: %s\r\n"), _contentType.c_str());
|
||||
out.concat(buf);
|
||||
}
|
||||
buffer.concat(version);
|
||||
buffer.concat(' ');
|
||||
buffer.concat(_code);
|
||||
buffer.concat(' ');
|
||||
buffer.concat(responseCodeToString(_code));
|
||||
buffer.concat(T_rn);
|
||||
|
||||
// Add headers
|
||||
for (const auto& header : _headers) {
|
||||
snprintf_P(buf, bufSize, PSTR("%s: %s\r\n"), header.name().c_str(), header.value().c_str());
|
||||
out.concat(buf);
|
||||
buffer.concat(header.name());
|
||||
#ifdef ESP8266
|
||||
buffer.concat(PSTR(": "));
|
||||
#else
|
||||
buffer.concat(": ");
|
||||
#endif
|
||||
buffer.concat(header.value());
|
||||
buffer.concat(T_rn);
|
||||
}
|
||||
_headers.clear();
|
||||
|
||||
out.concat(T_rn);
|
||||
_headLength = out.length();
|
||||
return out;
|
||||
buffer.concat(T_rn);
|
||||
_headLength = buffer.length();
|
||||
}
|
||||
|
||||
bool AsyncWebServerResponse::_started() const { return _state > RESPONSE_SETUP; }
|
||||
@ -337,7 +356,8 @@ AsyncBasicResponse::AsyncBasicResponse(int code, const char* contentType, const
|
||||
|
||||
void AsyncBasicResponse::_respond(AsyncWebServerRequest* request) {
|
||||
_state = RESPONSE_HEADERS;
|
||||
String out = _assembleHead(request->version());
|
||||
String out;
|
||||
_assembleHead(out, request->version());
|
||||
size_t outLen = out.length();
|
||||
size_t space = request->client()->space();
|
||||
if (!_contentLength && space >= outLen) {
|
||||
@ -411,7 +431,7 @@ AsyncAbstractResponse::AsyncAbstractResponse(AwsTemplateProcessor callback) : _c
|
||||
|
||||
void AsyncAbstractResponse::_respond(AsyncWebServerRequest* request) {
|
||||
addHeader(T_Connection, T_close, false);
|
||||
_head = _assembleHead(request->version());
|
||||
_assembleHead(_head, request->version());
|
||||
_state = RESPONSE_HEADERS;
|
||||
_ack(request, 0, 0);
|
||||
}
|
||||
@ -472,9 +492,7 @@ size_t AsyncAbstractResponse::_ack(AsyncWebServerRequest* request, size_t len, u
|
||||
free(buf);
|
||||
return 0;
|
||||
}
|
||||
outLen = sprintf_P((char*)buf + headLen, PSTR("%x"), readLen) + headLen;
|
||||
while (outLen < headLen + 4)
|
||||
buf[outLen++] = ' ';
|
||||
outLen = sprintf((char*)buf+headLen, "%04x", readLen) + headLen;
|
||||
buf[outLen++] = '\r';
|
||||
buf[outLen++] = '\n';
|
||||
outLen += readLen;
|
||||
|
Loading…
Reference in New Issue
Block a user