Aktualizace na verzi 3.3.23

This commit is contained in:
2024-12-05 10:21:12 +01:00
parent 2333497adc
commit 7c828c70d8
36 changed files with 1436 additions and 1204 deletions

View File

@ -141,6 +141,9 @@ size_t AsyncEventSourceMessage::ack(size_t len, __attribute__((unused)) uint32_t
}
size_t AsyncEventSourceMessage::write(AsyncClient* client) {
if (!client)
return 0;
if (_sent >= _len || !client->canSend()) {
return 0;
}
@ -186,7 +189,10 @@ AsyncEventSourceClient::~AsyncEventSourceClient() {
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
// length() is not thread-safe, thus acquiring the lock before this call..
std::lock_guard<std::mutex> lock(_lockmq);
@ -198,7 +204,7 @@ void AsyncEventSourceClient::_queueMessage(const char* message, size_t len) {
#elif defined(ESP32)
log_e("Too many messages queued: deleting message");
#endif
return;
return false;
}
_messageQueue.emplace_back(message, len);
@ -206,6 +212,8 @@ void AsyncEventSourceClient::_queueMessage(const char* message, size_t len) {
if (_client->canSend()) {
_runQueue();
}
return true;
}
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))) {
_client->close(true);
if (_client)
_client->close(true);
}
void AsyncEventSourceClient::_onDisconnect() {
_client = NULL;
if (!_client)
return;
_client = nullptr;
_server->_handleDisconnect(this);
}
void AsyncEventSourceClient::close() {
if (_client != NULL)
if (_client)
_client->close();
}
void AsyncEventSourceClient::write(const char* message, size_t len) {
if (!connected())
return;
_queueMessage(message, len);
bool AsyncEventSourceClient::write(const char* message, size_t len) {
return connected() && _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())
return;
return false;
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 {
@ -261,6 +270,9 @@ size_t AsyncEventSourceClient::packetsWaiting() const {
}
void AsyncEventSourceClient::_runQueue() {
if (!_client)
return;
size_t total_bytes_written = 0;
for (auto i = _messageQueue.begin(); i != _messageQueue.end(); ++i) {
if (!i->sent()) {
@ -270,6 +282,7 @@ void AsyncEventSourceClient::_runQueue() {
break;
}
}
if (total_bytes_written > 0)
_client->send();
@ -282,11 +295,6 @@ void AsyncEventSourceClient::_runQueue() {
}
}
// Handler
void AsyncEventSource::onConnect(ArEventHandlerFunction cb) {
_connectcb = cb;
}
void AsyncEventSource::authorizeConnect(ArAuthorizeConnectHandler cb) {
AuthorizationMiddleware* m = new AuthorizationMiddleware(401, cb);
m->_freeOnRemoval = true;
@ -308,6 +316,8 @@ void AsyncEventSource::_handleDisconnect(AsyncEventSourceClient* client) {
#ifdef ESP32
std::lock_guard<std::mutex> lock(_client_queue_lock);
#endif
if (_disconnectcb)
_disconnectcb(client);
for (auto i = _clients.begin(); i != _clients.end(); ++i) {
if (i->get() == client)
_clients.erase(i);
@ -346,17 +356,21 @@ size_t AsyncEventSource::avgPacketsWaiting() const {
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) {
String ev = generateEventMessage(message, event, id, reconnect);
#ifdef ESP32
std::lock_guard<std::mutex> lock(_client_queue_lock);
#endif
size_t hits = 0;
size_t miss = 0;
for (const auto& c : _clients) {
if (c->connected()) {
c->write(ev.c_str(), ev.length());
}
if (c->write(ev.c_str(), ev.length()))
++hits;
else
++miss;
}
return hits == 0 ? DISCARDED : (miss == 0 ? ENQUEUED : PARTIALLY_ENQUEUED);
}
size_t AsyncEventSource::count() const {
@ -371,11 +385,8 @@ size_t AsyncEventSource::count() const {
return n_clients;
}
bool AsyncEventSource::canHandle(AsyncWebServerRequest* request) {
if (request->method() != HTTP_GET || !request->url().equals(_url)) {
return false;
}
return true;
bool AsyncEventSource::canHandle(AsyncWebServerRequest* request) const {
return request->isSSE() && request->url().equals(_url);
}
void AsyncEventSource::handleRequest(AsyncWebServerRequest* request) {

View File

@ -81,7 +81,7 @@ class AsyncEventSourceClient {
#ifdef ESP32
mutable std::mutex _lockmq;
#endif
void _queueMessage(const char* message, size_t len);
bool _queueMessage(const char* message, size_t len);
void _runQueue();
public:
@ -90,11 +90,11 @@ 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(); }
bool write(const char* message, size_t len);
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); }
bool send(const String& message, const char* event, uint32_t id = 0, uint32_t reconnect = 0) { return send(message.c_str(), event, id, reconnect); }
bool send(const char* message, const char* event = NULL, uint32_t id = 0, uint32_t reconnect = 0);
bool connected() const { return _client && _client->connected(); }
uint32_t lastId() const { return _lastId; }
size_t packetsWaiting() const;
@ -114,19 +114,28 @@ class AsyncEventSource : public AsyncWebHandler {
// since simultaneous access from different tasks is possible
mutable std::mutex _client_queue_lock;
#endif
ArEventHandlerFunction _connectcb{nullptr};
ArEventHandlerFunction _connectcb = nullptr;
ArEventHandlerFunction _disconnectcb = nullptr;
public:
typedef enum {
DISCARDED = 0,
ENQUEUED = 1,
PARTIALLY_ENQUEUED = 2,
} SendStatus;
AsyncEventSource(const String& url) : _url(url) {};
~AsyncEventSource() { close(); };
const char* url() const { return _url.c_str(); }
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 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);
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); }
SendStatus send(const String& message, const char* event, uint32_t id = 0, uint32_t reconnect = 0) { return send(message.c_str(), event, id, reconnect); }
SendStatus send(const char* message, const char* event = NULL, uint32_t id = 0, uint32_t reconnect = 0);
// number of clients connected
size_t count() const;
size_t avgPacketsWaiting() const;
@ -134,8 +143,8 @@ class AsyncEventSource : public AsyncWebHandler {
// system callbacks (do not call)
void _addClient(AsyncEventSourceClient* client);
void _handleDisconnect(AsyncEventSourceClient* client);
virtual bool canHandle(AsyncWebServerRequest* request) override final;
virtual void handleRequest(AsyncWebServerRequest* request) override final;
bool canHandle(AsyncWebServerRequest* request) const override final;
void handleRequest(AsyncWebServerRequest* request) override final;
};
class AsyncEventSourceResponse : public AsyncWebServerResponse {

View File

@ -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) {}
#endif
bool AsyncCallbackJsonWebHandler::canHandle(AsyncWebServerRequest* request) {
if (!_onRequest)
return false;
WebRequestMethodComposite request_method = request->method();
if (!(_method & request_method))
bool AsyncCallbackJsonWebHandler::canHandle(AsyncWebServerRequest* request) const {
if (!_onRequest || !request->isHTTP() || !(_method & request->method()))
return false;
if (_uri.length() && (_uri != request->url() && !request->url().startsWith(_uri + "/")))
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 true;

View File

@ -119,11 +119,11 @@ class AsyncCallbackJsonWebHandler : public AsyncWebHandler {
void setMaxContentLength(int maxContentLength) { _maxContentLength = maxContentLength; }
void onRequest(ArJsonRequestHandlerFunction fn) { _onRequest = fn; }
virtual bool canHandle(AsyncWebServerRequest* request) override final;
virtual 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 {}
virtual 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 canHandle(AsyncWebServerRequest* request) const override final;
void handleRequest(AsyncWebServerRequest* request) 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 {}
void handleBody(AsyncWebServerRequest* request, uint8_t* data, size_t len, size_t index, size_t total) override final;
bool isRequestHandlerTrivial() const override final { return !_onRequest; }
};
#endif // ASYNC_JSON_SUPPORT == 1

View File

@ -44,18 +44,14 @@ AsyncCallbackMessagePackWebHandler::AsyncCallbackMessagePackWebHandler(const Str
: _uri(uri), _method(HTTP_GET | HTTP_POST | HTTP_PUT | HTTP_PATCH), _onRequest(onRequest), _maxContentLength(16384) {}
#endif
bool AsyncCallbackMessagePackWebHandler::canHandle(AsyncWebServerRequest* request) {
if (!_onRequest)
return false;
WebRequestMethodComposite request_method = request->method();
if (!(_method & request_method))
bool AsyncCallbackMessagePackWebHandler::canHandle(AsyncWebServerRequest* request) const {
if (!_onRequest || !request->isHTTP() || !(_method & request->method()))
return false;
if (_uri.length() && (_uri != request->url() && !request->url().startsWith(_uri + "/")))
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 true;

View File

@ -92,11 +92,11 @@ class AsyncCallbackMessagePackWebHandler : public AsyncWebHandler {
void setMaxContentLength(int maxContentLength) { _maxContentLength = maxContentLength; }
void onRequest(ArMessagePackRequestHandlerFunction fn) { _onRequest = fn; }
virtual bool canHandle(AsyncWebServerRequest* request) override final;
virtual 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 {}
virtual 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 canHandle(AsyncWebServerRequest* request) const override final;
void handleRequest(AsyncWebServerRequest* request) 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 {}
void handleBody(AsyncWebServerRequest* request, uint8_t* data, size_t len, size_t index, size_t total) override final;
bool isRequestHandlerTrivial() const override final { return !_onRequest; }
};
#endif // ASYNC_MSG_PACK_SUPPORT == 1

View File

@ -39,7 +39,7 @@
using namespace asyncsrv;
size_t webSocketSendFrameWindow(AsyncClient* client) {
if (!client->canSend())
if (!client || !client->canSend())
return 0;
size_t space = client->space();
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) {
if (!client->canSend()) {
if (!client || !client->canSend()) {
// Serial.println("SF 1");
return 0;
}
@ -185,12 +185,12 @@ class AsyncWebSocketControl {
_data = NULL;
}
virtual ~AsyncWebSocketControl() {
~AsyncWebSocketControl() {
if (_data != NULL)
free(_data);
}
virtual bool finished() const { return _finished; }
bool finished() const { return _finished; }
uint8_t opcode() { return _opcode; }
uint8_t len() { return _len + 2; }
size_t send(AsyncClient* client) {
@ -219,6 +219,9 @@ void AsyncWebSocketMessage::ack(size_t len, uint32_t time) {
}
size_t AsyncWebSocketMessage::send(AsyncClient* client) {
if (!client)
return 0;
if (_status != WS_MSG_SENDING)
return 0;
if (_acked < _ack) {
@ -343,7 +346,7 @@ void AsyncWebSocketClient::_onPoll() {
#ifdef ESP32
std::unique_lock<std::mutex> lock(_lock);
#endif
if (_client->canSend() && (!_controlQueue.empty() || !_messageQueue.empty())) {
if (_client && _client->canSend() && (!_controlQueue.empty() || !_messageQueue.empty())) {
_runQueue();
} else if (_keepAlivePeriod > 0 && (millis() - _lastMessageTime) >= _keepAlivePeriod && (_controlQueue.empty() && _messageQueue.empty())) {
#ifdef ESP32
@ -371,16 +374,13 @@ bool AsyncWebSocketClient::queueIsFull() const {
#ifdef ESP32
std::lock_guard<std::mutex> lock(_lock);
#endif
size_t size = _messageQueue.size();
;
return (size >= WS_MAX_QUEUED_MESSAGES) || (_status != WS_CONNECTED);
return (_messageQueue.size() >= WS_MAX_QUEUED_MESSAGES) || (_status != WS_CONNECTED);
}
size_t AsyncWebSocketClient::queueLen() const {
#ifdef ESP32
std::lock_guard<std::mutex> lock(_lock);
#endif
return _messageQueue.size();
}
@ -391,38 +391,43 @@ bool AsyncWebSocketClient::canSend() const {
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)
return;
{
#ifdef ESP32
std::lock_guard<std::mutex> lock(_lock);
#endif
_controlQueue.emplace_back(opcode, data, len, mask);
}
if (_client && _client->canSend())
_runQueue();
}
void AsyncWebSocketClient::_queueMessage(AsyncWebSocketSharedBuffer buffer, uint8_t opcode, bool mask) {
if (!_client || buffer->size() == 0 || _status != WS_CONNECTED)
return;
return false;
#ifdef ESP32
std::lock_guard<std::mutex> lock(_lock);
#endif
_controlQueue.emplace_back(opcode, data, len, mask);
if (_client && _client->canSend())
_runQueue();
return true;
}
bool AsyncWebSocketClient::_queueMessage(AsyncWebSocketSharedBuffer buffer, uint8_t opcode, bool mask) {
if (!_client || buffer->size() == 0 || _status != WS_CONNECTED)
return false;
#ifdef ESP32
std::lock_guard<std::mutex> lock(_lock);
#endif
if (_messageQueue.size() >= WS_MAX_QUEUED_MESSAGES) {
if (closeWhenFull) {
_status = WS_DISCONNECTED;
if (_client)
_client->close(true);
#ifdef ESP8266
ets_printf("AsyncWebSocketClient::_queueMessage: Too many messages queued: closing connection\n");
#elif defined(ESP32)
log_e("Too many messages queued: closing connection");
#endif
_status = WS_DISCONNECTED;
if (_client)
_client->close(true);
} else {
#ifdef ESP8266
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");
#endif
}
return;
} else {
_messageQueue.emplace_back(buffer, opcode, mask);
return false;
}
_messageQueue.emplace_back(buffer, opcode, mask);
if (_client && _client->canSend())
_runQueue();
return true;
}
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);
}
void AsyncWebSocketClient::ping(const uint8_t* data, size_t len) {
if (_status == WS_CONNECTED)
_queueControl(WS_PING, data, len);
bool AsyncWebSocketClient::ping(const uint8_t* data, size_t len) {
return _status == WS_CONNECTED && _queueControl(WS_PING, data, len);
}
void AsyncWebSocketClient::_onError(int8_t) {
@ -476,6 +483,8 @@ void AsyncWebSocketClient::_onError(int8_t) {
}
void AsyncWebSocketClient::_onTimeout(uint32_t time) {
if (!_client)
return;
// Serial.println("onTime");
(void)time;
_client->close(true);
@ -483,7 +492,7 @@ void AsyncWebSocketClient::_onTimeout(uint32_t time) {
void AsyncWebSocketClient::_onDisconnect() {
// Serial.println("onDis");
_client = NULL;
_client = nullptr;
}
void AsyncWebSocketClient::_onData(void* pbuf, size_t plen) {
@ -535,7 +544,7 @@ void AsyncWebSocketClient::_onData(void* pbuf, size_t plen) {
}
}
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;
} else if ((datalen + _pinfo.index) == _pinfo.len) {
@ -550,18 +559,21 @@ void AsyncWebSocketClient::_onData(void* pbuf, size_t plen) {
}
if (_status == WS_DISCONNECTING) {
_status = WS_DISCONNECTED;
_client->close(true);
if (_client)
_client->close(true);
} else {
_status = WS_DISCONNECTING;
_client->ackLater();
if (_client)
_client->ackLater();
_queueControl(WS_DISCONNECT, data, datalen);
}
} else if (_pinfo.opcode == WS_PING) {
_server->_handleEvent(this, WS_EVT_PING, NULL, NULL, 0);
_queueControl(WS_PONG, data, datalen);
} else if (_pinfo.opcode == WS_PONG) {
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);
} else if (_pinfo.opcode < 8) { // continuation or text/binary frame
_server->_handleEvent(this, WS_EVT_PONG, NULL, NULL, 0);
} else if (_pinfo.opcode < WS_DISCONNECT) { // continuation or text/binary frame
_server->_handleEvent(this, WS_EVT_DATA, (void*)&_pinfo, data, datalen);
if (_pinfo.final)
_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;
if (datalen > 0)
if (datalen)
data[datalen] = datalast;
data += datalen;
@ -601,9 +613,9 @@ size_t AsyncWebSocketClient::printf(const char* format, ...) {
len = vsnprintf(buffer, len + 1, format, arg);
va_end(arg);
text(buffer, len);
bool enqueued = text(buffer, len);
delete[] buffer;
return len;
return enqueued ? len : 0;
}
#ifdef ESP8266
@ -625,9 +637,9 @@ size_t AsyncWebSocketClient::printf_P(PGM_P formatP, ...) {
len = vsnprintf_P(buffer, len + 1, formatP, arg);
va_end(arg);
text(buffer, len);
bool enqueued = text(buffer, len);
delete[] buffer;
return len;
return enqueued ? len : 0;
}
#endif
@ -639,35 +651,37 @@ namespace {
}
}
void AsyncWebSocketClient::text(AsyncWebSocketMessageBuffer* buffer) {
bool AsyncWebSocketClient::text(AsyncWebSocketMessageBuffer* buffer) {
bool enqueued = false;
if (buffer) {
text(std::move(buffer->_buffer));
enqueued = text(std::move(buffer->_buffer));
delete buffer;
}
return enqueued;
}
void AsyncWebSocketClient::text(AsyncWebSocketSharedBuffer buffer) {
_queueMessage(buffer);
bool AsyncWebSocketClient::text(AsyncWebSocketSharedBuffer buffer) {
return _queueMessage(buffer);
}
void AsyncWebSocketClient::text(const uint8_t* message, size_t len) {
text(makeSharedBuffer(message, len));
bool AsyncWebSocketClient::text(const uint8_t* message, size_t len) {
return text(makeSharedBuffer(message, len));
}
void AsyncWebSocketClient::text(const char* message, size_t len) {
text((const uint8_t*)message, len);
bool AsyncWebSocketClient::text(const char* message, size_t len) {
return text((const uint8_t*)message, len);
}
void AsyncWebSocketClient::text(const char* message) {
text(message, strlen(message));
bool AsyncWebSocketClient::text(const char* message) {
return text(message, strlen(message));
}
void AsyncWebSocketClient::text(const String& message) {
text(message.c_str(), message.length());
bool AsyncWebSocketClient::text(const String& message) {
return text(message.c_str(), message.length());
}
#ifdef ESP8266
void AsyncWebSocketClient::text(const __FlashStringHelper* data) {
bool AsyncWebSocketClient::text(const __FlashStringHelper* data) {
PGM_P p = reinterpret_cast<PGM_P>(data);
size_t n = 0;
@ -678,51 +692,57 @@ void AsyncWebSocketClient::text(const __FlashStringHelper* data) {
}
char* message = (char*)malloc(n + 1);
bool enqueued = false;
if (message) {
memcpy_P(message, p, n);
message[n] = 0;
text(message, n);
enqueued = text(message, n);
free(message);
}
return enqueued;
}
#endif // ESP8266
void AsyncWebSocketClient::binary(AsyncWebSocketMessageBuffer* buffer) {
bool AsyncWebSocketClient::binary(AsyncWebSocketMessageBuffer* buffer) {
bool enqueued = false;
if (buffer) {
binary(std::move(buffer->_buffer));
enqueued = binary(std::move(buffer->_buffer));
delete buffer;
}
return enqueued;
}
void AsyncWebSocketClient::binary(AsyncWebSocketSharedBuffer buffer) {
_queueMessage(buffer, WS_BINARY);
bool AsyncWebSocketClient::binary(AsyncWebSocketSharedBuffer buffer) {
return _queueMessage(buffer, WS_BINARY);
}
void AsyncWebSocketClient::binary(const uint8_t* message, size_t len) {
binary(makeSharedBuffer(message, len));
bool AsyncWebSocketClient::binary(const uint8_t* message, size_t len) {
return binary(makeSharedBuffer(message, len));
}
void AsyncWebSocketClient::binary(const char* message, size_t len) {
binary((const uint8_t*)message, len);
bool AsyncWebSocketClient::binary(const char* message, size_t len) {
return binary((const uint8_t*)message, len);
}
void AsyncWebSocketClient::binary(const char* message) {
binary(message, strlen(message));
bool AsyncWebSocketClient::binary(const char* message) {
return binary(message, strlen(message));
}
void AsyncWebSocketClient::binary(const String& message) {
binary(message.c_str(), message.length());
bool AsyncWebSocketClient::binary(const String& message) {
return binary(message.c_str(), message.length());
}
#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);
char* message = (char*)malloc(len);
bool enqueued = false;
if (message) {
memcpy_P(message, p, len);
binary(message, len);
enqueued = binary(message, len);
free(message);
}
return enqueued;
}
#endif
@ -801,33 +821,38 @@ void AsyncWebSocket::cleanupClients(uint16_t maxClients) {
}
}
void AsyncWebSocket::ping(uint32_t id, const uint8_t* data, size_t len) {
if (AsyncWebSocketClient* c = client(id))
c->ping(data, len);
bool AsyncWebSocket::ping(uint32_t id, const uint8_t* data, size_t len) {
AsyncWebSocketClient* c = client(id);
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)
if (c.status() == WS_CONNECTED)
c.ping(data, len);
if (c.status() == WS_CONNECTED && 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) {
if (AsyncWebSocketClient* c = client(id))
c->text(makeSharedBuffer(message, len));
bool AsyncWebSocket::text(uint32_t id, const uint8_t* message, size_t len) {
AsyncWebSocketClient* c = client(id);
return c && c->text(makeSharedBuffer(message, len));
}
void AsyncWebSocket::text(uint32_t id, const char* message, size_t len) {
text(id, (const uint8_t*)message, len);
bool AsyncWebSocket::text(uint32_t id, const char* message, size_t len) {
return text(id, (const uint8_t*)message, len);
}
void AsyncWebSocket::text(uint32_t id, const char* message) {
text(id, message, strlen(message));
bool AsyncWebSocket::text(uint32_t id, const char* message) {
return text(id, message, strlen(message));
}
void AsyncWebSocket::text(uint32_t id, const String& message) {
text(id, message.c_str(), message.length());
bool AsyncWebSocket::text(uint32_t id, const String& message) {
return text(id, message.c_str(), message.length());
}
#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);
size_t n = 0;
@ -838,40 +863,44 @@ void AsyncWebSocket::text(uint32_t id, const __FlashStringHelper* data) {
}
char* message = (char*)malloc(n + 1);
bool enqueued = false;
if (message) {
memcpy_P(message, p, n);
message[n] = 0;
text(id, message, n);
enqueued = text(id, message, n);
free(message);
}
return enqueued;
}
#endif // ESP8266
void AsyncWebSocket::text(uint32_t id, AsyncWebSocketMessageBuffer* buffer) {
bool AsyncWebSocket::text(uint32_t id, AsyncWebSocketMessageBuffer* buffer) {
bool enqueued = false;
if (buffer) {
text(id, std::move(buffer->_buffer));
enqueued = text(id, std::move(buffer->_buffer));
delete buffer;
}
return enqueued;
}
void AsyncWebSocket::text(uint32_t id, AsyncWebSocketSharedBuffer buffer) {
if (AsyncWebSocketClient* c = client(id))
c->text(buffer);
bool AsyncWebSocket::text(uint32_t id, AsyncWebSocketSharedBuffer buffer) {
AsyncWebSocketClient* c = client(id);
return c && c->text(buffer);
}
void AsyncWebSocket::textAll(const uint8_t* message, size_t len) {
textAll(makeSharedBuffer(message, len));
AsyncWebSocket::SendStatus AsyncWebSocket::textAll(const uint8_t* message, size_t len) {
return textAll(makeSharedBuffer(message, len));
}
void AsyncWebSocket::textAll(const char* message, size_t len) {
textAll((const uint8_t*)message, len);
AsyncWebSocket::SendStatus AsyncWebSocket::textAll(const char* message, size_t len) {
return textAll((const uint8_t*)message, len);
}
void AsyncWebSocket::textAll(const char* message) {
textAll(message, strlen(message));
AsyncWebSocket::SendStatus AsyncWebSocket::textAll(const char* message) {
return textAll(message, strlen(message));
}
void AsyncWebSocket::textAll(const String& message) {
textAll(message.c_str(), message.length());
AsyncWebSocket::SendStatus AsyncWebSocket::textAll(const String& message) {
return textAll(message.c_str(), message.length());
}
#ifdef ESP8266
void AsyncWebSocket::textAll(const __FlashStringHelper* data) {
AsyncWebSocket::SendStatus AsyncWebSocket::textAll(const __FlashStringHelper* data) {
PGM_P p = reinterpret_cast<PGM_P>(data);
size_t n = 0;
@ -882,99 +911,121 @@ void AsyncWebSocket::textAll(const __FlashStringHelper* data) {
}
char* message = (char*)malloc(n + 1);
AsyncWebSocket::SendStatus status = DISCARDED;
if (message) {
memcpy_P(message, p, n);
message[n] = 0;
textAll(message, n);
status = textAll(message, n);
free(message);
}
return status;
}
#endif // ESP8266
void AsyncWebSocket::textAll(AsyncWebSocketMessageBuffer* buffer) {
AsyncWebSocket::SendStatus AsyncWebSocket::textAll(AsyncWebSocketMessageBuffer* buffer) {
AsyncWebSocket::SendStatus status = DISCARDED;
if (buffer) {
textAll(std::move(buffer->_buffer));
status = textAll(std::move(buffer->_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)
if (c.status() == WS_CONNECTED)
c.text(buffer);
if (c.status() == WS_CONNECTED && 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) {
if (AsyncWebSocketClient* c = client(id))
c->binary(makeSharedBuffer(message, len));
bool AsyncWebSocket::binary(uint32_t id, const uint8_t* message, size_t len) {
AsyncWebSocketClient* c = client(id);
return c && c->binary(makeSharedBuffer(message, len));
}
void AsyncWebSocket::binary(uint32_t id, const char* message, size_t len) {
binary(id, (const uint8_t*)message, len);
bool AsyncWebSocket::binary(uint32_t id, const char* message, size_t len) {
return binary(id, (const uint8_t*)message, len);
}
void AsyncWebSocket::binary(uint32_t id, const char* message) {
binary(id, message, strlen(message));
bool AsyncWebSocket::binary(uint32_t id, const char* message) {
return binary(id, message, strlen(message));
}
void AsyncWebSocket::binary(uint32_t id, const String& message) {
binary(id, message.c_str(), message.length());
bool AsyncWebSocket::binary(uint32_t id, const String& message) {
return binary(id, message.c_str(), message.length());
}
#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);
char* message = (char*)malloc(len);
bool enqueued = false;
if (message) {
memcpy_P(message, p, len);
binary(id, message, len);
enqueued = binary(id, message, len);
free(message);
}
return enqueued;
}
#endif // ESP8266
void AsyncWebSocket::binary(uint32_t id, AsyncWebSocketMessageBuffer* buffer) {
bool AsyncWebSocket::binary(uint32_t id, AsyncWebSocketMessageBuffer* buffer) {
bool enqueued = false;
if (buffer) {
binary(id, std::move(buffer->_buffer));
enqueued = binary(id, std::move(buffer->_buffer));
delete buffer;
}
return enqueued;
}
void AsyncWebSocket::binary(uint32_t id, AsyncWebSocketSharedBuffer buffer) {
if (AsyncWebSocketClient* c = client(id))
c->binary(buffer);
bool AsyncWebSocket::binary(uint32_t id, AsyncWebSocketSharedBuffer buffer) {
AsyncWebSocketClient* c = client(id);
return c && c->binary(buffer);
}
void AsyncWebSocket::binaryAll(const uint8_t* message, size_t len) {
binaryAll(makeSharedBuffer(message, len));
AsyncWebSocket::SendStatus AsyncWebSocket::binaryAll(const uint8_t* message, size_t len) {
return binaryAll(makeSharedBuffer(message, len));
}
void AsyncWebSocket::binaryAll(const char* message, size_t len) {
binaryAll((const uint8_t*)message, len);
AsyncWebSocket::SendStatus AsyncWebSocket::binaryAll(const char* message, size_t len) {
return binaryAll((const uint8_t*)message, len);
}
void AsyncWebSocket::binaryAll(const char* message) {
binaryAll(message, strlen(message));
AsyncWebSocket::SendStatus AsyncWebSocket::binaryAll(const char* message) {
return binaryAll(message, strlen(message));
}
void AsyncWebSocket::binaryAll(const String& message) {
binaryAll(message.c_str(), message.length());
AsyncWebSocket::SendStatus AsyncWebSocket::binaryAll(const String& message) {
return binaryAll(message.c_str(), message.length());
}
#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);
char* message = (char*)malloc(len);
AsyncWebSocket::SendStatus status = DISCARDED;
if (message) {
memcpy_P(message, p, len);
binaryAll(message, len);
status = binaryAll(message, len);
free(message);
}
return status;
}
#endif // ESP8266
void AsyncWebSocket::binaryAll(AsyncWebSocketMessageBuffer* buffer) {
AsyncWebSocket::SendStatus AsyncWebSocket::binaryAll(AsyncWebSocketMessageBuffer* buffer) {
AsyncWebSocket::SendStatus status = DISCARDED;
if (buffer) {
binaryAll(std::move(buffer->_buffer));
status = binaryAll(std::move(buffer->_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)
if (c.status() == WS_CONNECTED)
c.binary(buffer);
if (c.status() == WS_CONNECTED && 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, ...) {
@ -1007,9 +1058,9 @@ size_t AsyncWebSocket::printfAll(const char* format, ...) {
len = vsnprintf(buffer, len + 1, format, arg);
va_end(arg);
textAll(buffer, len);
AsyncWebSocket::SendStatus status = textAll(buffer, len);
delete[] buffer;
return len;
return status == DISCARDED ? 0 : len;
}
#ifdef ESP8266
@ -1043,9 +1094,9 @@ size_t AsyncWebSocket::printfAll_P(PGM_P formatP, ...) {
len = vsnprintf_P(buffer, len + 1, formatP, arg);
va_end(arg);
textAll(buffer, len);
AsyncWebSocket::SendStatus status = textAll(buffer, len);
delete[] buffer;
return len;
return status == DISCARDED ? 0 : len;
}
#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_UUID FPSTR(__WS_STR_UUID)
bool AsyncWebSocket::canHandle(AsyncWebServerRequest* request) {
if (!_enabled)
return false;
if (request->method() != HTTP_GET || !request->url().equals(_url) || !request->isExpectedRequestedConnType(RCT_WS))
return false;
return true;
bool AsyncWebSocket::canHandle(AsyncWebServerRequest* request) const {
return _enabled && request->isWebSocketUpgrade() && request->url().equals(_url);
}
void AsyncWebSocket::handleRequest(AsyncWebServerRequest* request) {

View File

@ -104,6 +104,7 @@ typedef enum { WS_MSG_SENDING,
WS_MSG_ERROR } AwsMessageStatus;
typedef enum { WS_EVT_CONNECT,
WS_EVT_DISCONNECT,
WS_EVT_PING,
WS_EVT_PONG,
WS_EVT_ERROR,
WS_EVT_DATA } AwsEventType;
@ -164,8 +165,8 @@ class AsyncWebSocketClient {
uint32_t _lastMessageTime;
uint32_t _keepAlivePeriod;
void _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 _queueControl(uint8_t opcode, const uint8_t* data = NULL, size_t len = 0, bool mask = false);
bool _queueMessage(AsyncWebSocketSharedBuffer buffer, uint8_t opcode = WS_TEXT, bool mask = false);
void _runQueue();
void _clearQueue();
@ -212,7 +213,7 @@ class AsyncWebSocketClient {
// control frames
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)
void keepAlivePeriod(uint16_t seconds) {
@ -229,19 +230,19 @@ class AsyncWebSocketClient {
size_t printf(const char* format, ...) __attribute__((format(printf, 2, 3)));
void text(AsyncWebSocketSharedBuffer buffer);
void text(const uint8_t* message, size_t len);
void text(const char* message, size_t len);
void text(const char* message);
void text(const String& message);
void text(AsyncWebSocketMessageBuffer* buffer);
bool text(AsyncWebSocketSharedBuffer buffer);
bool text(const uint8_t* message, size_t len);
bool text(const char* message, size_t len);
bool text(const char* message);
bool text(const String& message);
bool text(AsyncWebSocketMessageBuffer* buffer);
void binary(AsyncWebSocketSharedBuffer buffer);
void binary(const uint8_t* message, size_t len);
void binary(const char* message, size_t len);
void binary(const char* message);
void binary(const String& message);
void binary(AsyncWebSocketMessageBuffer* buffer);
bool binary(AsyncWebSocketSharedBuffer buffer);
bool binary(const uint8_t* message, size_t len);
bool binary(const char* message, size_t len);
bool binary(const char* message);
bool binary(const String& message);
bool binary(AsyncWebSocketMessageBuffer* buffer);
bool canSend() const;
@ -255,8 +256,8 @@ class AsyncWebSocketClient {
#ifdef ESP8266
size_t printf_P(PGM_P formatP, ...) __attribute__((format(printf, 2, 3)));
void text(const __FlashStringHelper* message);
void binary(const __FlashStringHelper* message, size_t len);
bool text(const __FlashStringHelper* message);
bool binary(const __FlashStringHelper* message, size_t len);
#endif
};
@ -277,6 +278,12 @@ class AsyncWebSocket : public AsyncWebHandler {
#endif
public:
typedef enum {
DISCARDED = 0,
ENQUEUED = 1,
PARTIALLY_ENQUEUED = 2,
} SendStatus;
explicit AsyncWebSocket(const char* url) : _url(url), _cNextId(1), _enabled(true) {}
AsyncWebSocket(const String& url) : _url(url), _cNextId(1), _enabled(true) {}
~AsyncWebSocket() {};
@ -294,45 +301,45 @@ class AsyncWebSocket : public AsyncWebHandler {
void closeAll(uint16_t code = 0, const char* message = NULL);
void cleanupClients(uint16_t maxClients = DEFAULT_MAX_WS_CLIENTS);
void 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
bool ping(uint32_t id, const uint8_t* data = NULL, size_t len = 0);
SendStatus pingAll(const uint8_t* data = NULL, size_t len = 0); // done
void text(uint32_t id, const uint8_t* message, size_t len);
void text(uint32_t id, const char* message, size_t len);
void text(uint32_t id, const char* message);
void text(uint32_t id, const String& message);
void text(uint32_t id, AsyncWebSocketMessageBuffer* buffer);
void text(uint32_t id, AsyncWebSocketSharedBuffer buffer);
bool text(uint32_t id, const uint8_t* message, size_t len);
bool text(uint32_t id, const char* message, size_t len);
bool text(uint32_t id, const char* message);
bool text(uint32_t id, const String& message);
bool text(uint32_t id, AsyncWebSocketMessageBuffer* buffer);
bool text(uint32_t id, AsyncWebSocketSharedBuffer buffer);
void textAll(const uint8_t* message, size_t len);
void textAll(const char* message, size_t len);
void textAll(const char* message);
void textAll(const String& message);
void textAll(AsyncWebSocketMessageBuffer* buffer);
void textAll(AsyncWebSocketSharedBuffer buffer);
SendStatus textAll(const uint8_t* message, size_t len);
SendStatus textAll(const char* message, size_t len);
SendStatus textAll(const char* message);
SendStatus textAll(const String& message);
SendStatus textAll(AsyncWebSocketMessageBuffer* buffer);
SendStatus textAll(AsyncWebSocketSharedBuffer buffer);
void binary(uint32_t id, const uint8_t* message, size_t len);
void binary(uint32_t id, const char* message, size_t len);
void binary(uint32_t id, const char* message);
void binary(uint32_t id, const String& message);
void binary(uint32_t id, AsyncWebSocketMessageBuffer* buffer);
void binary(uint32_t id, AsyncWebSocketSharedBuffer buffer);
bool binary(uint32_t id, const uint8_t* message, size_t len);
bool binary(uint32_t id, const char* message, size_t len);
bool binary(uint32_t id, const char* message);
bool binary(uint32_t id, const String& message);
bool binary(uint32_t id, AsyncWebSocketMessageBuffer* buffer);
bool binary(uint32_t id, AsyncWebSocketSharedBuffer buffer);
void binaryAll(const uint8_t* message, size_t len);
void binaryAll(const char* message, size_t len);
void binaryAll(const char* message);
void binaryAll(const String& message);
void binaryAll(AsyncWebSocketMessageBuffer* buffer);
void binaryAll(AsyncWebSocketSharedBuffer buffer);
SendStatus binaryAll(const uint8_t* message, size_t len);
SendStatus binaryAll(const char* message, size_t len);
SendStatus binaryAll(const char* message);
SendStatus binaryAll(const String& message);
SendStatus binaryAll(AsyncWebSocketMessageBuffer* buffer);
SendStatus binaryAll(AsyncWebSocketSharedBuffer buffer);
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)));
#ifdef ESP8266
void text(uint32_t id, const __FlashStringHelper* message);
void textAll(const __FlashStringHelper* message);
void binary(uint32_t id, const __FlashStringHelper* message, size_t len);
void binaryAll(const __FlashStringHelper* message, size_t len);
bool text(uint32_t id, const __FlashStringHelper* message);
SendStatus textAll(const __FlashStringHelper* message);
bool binary(uint32_t id, 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 printfAll_P(PGM_P formatP, ...) __attribute__((format(printf, 2, 3)));
#endif
@ -344,8 +351,8 @@ class AsyncWebSocket : public AsyncWebHandler {
uint32_t _getNextId() { return _cNextId++; }
AsyncWebSocketClient* _newClient(AsyncWebServerRequest* request);
void _handleEvent(AsyncWebSocketClient* client, AwsEventType type, void* arg, uint8_t* data, size_t len);
virtual bool canHandle(AsyncWebServerRequest* request) override final;
virtual void handleRequest(AsyncWebServerRequest* request) override final;
bool canHandle(AsyncWebServerRequest* request) const override final;
void handleRequest(AsyncWebServerRequest* request) override final;
// messagebuffer functions/objects.
AsyncWebSocketMessageBuffer* makeBuffer(size_t size = 0);

View File

@ -12,7 +12,6 @@ class ChunkPrint : public Print {
public:
ChunkPrint(uint8_t* destination, size_t from, size_t len);
virtual ~ChunkPrint() {}
size_t write(uint8_t c);
size_t write(const uint8_t* buffer, size_t size) { return this->Print::write(buffer, size); }
};

View File

@ -48,10 +48,10 @@
#include "literals.h"
#define ASYNCWEBSERVER_VERSION "3.3.7"
#define ASYNCWEBSERVER_VERSION "3.3.23"
#define ASYNCWEBSERVER_VERSION_MAJOR 3
#define ASYNCWEBSERVER_VERSION_MINOR 3
#define ASYNCWEBSERVER_VERSION_REVISION 7
#define ASYNCWEBSERVER_VERSION_REVISION 23
#define ASYNCWEBSERVER_FORK_mathieucarbou
#ifdef ASYNCWEBSERVER_REGEX
@ -140,7 +140,6 @@ class AsyncWebHeader {
String _value;
public:
AsyncWebHeader() = default;
AsyncWebHeader(const AsyncWebHeader&) = default;
AsyncWebHeader(const char* name, const char* 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
typedef enum {
AUTH_NONE = 0,
AUTH_BASIC,
AUTH_DIGEST,
AUTH_BEARER,
AUTH_OTHER,
AUTH_NONE = 0, // always allow
AUTH_BASIC = 1,
AUTH_DIGEST = 2,
AUTH_BEARER = 3,
AUTH_OTHER = 4,
AUTH_DENIED = 255, // always returns 401
} AsyncAuthType;
typedef std::function<size_t(uint8_t*, size_t, size_t)> AwsResponseFiller;
@ -264,23 +264,21 @@ class AsyncWebServerRequest {
size_t contentLength() const { return _contentLength; }
bool multipart() const { return _isMultipart; }
#ifndef ESP8266
const char* methodToString() const;
const char* requestedConnTypeToString() const;
#else
const __FlashStringHelper* methodToString() const;
const __FlashStringHelper* requestedConnTypeToString() const;
#endif
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);
// hash is the string representation of:
// base64(user:pass) for basic or
// user:realm:md5(user:realm:pass) for digest
bool authenticate(const char* hash);
bool authenticate(const char* username, const char* credentials, const char* realm = NULL, bool isHash = false);
bool authenticate(const char* hash) const;
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(AsyncAuthType method, const char* realm = nullptr, const char* _authFailMsg = nullptr);
@ -523,9 +521,7 @@ using ArMiddlewareCallback = std::function<void(AsyncWebServerRequest* request,
class AsyncMiddleware {
public:
virtual ~AsyncMiddleware() {}
virtual void run(__unused AsyncWebServerRequest* request, __unused ArMiddlewareNext next) {
return next();
};
virtual void run(__unused AsyncWebServerRequest* request, __unused ArMiddlewareNext next) { return next(); };
private:
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
class AsyncMiddlewareChain {
public:
virtual ~AsyncMiddlewareChain();
~AsyncMiddlewareChain();
void addMiddleware(ArMiddlewareCallback fn);
void addMiddleware(AsyncMiddleware* middleware);
@ -570,13 +566,26 @@ class AuthenticationMiddleware : public AsyncMiddleware {
void setRealm(const char* realm) { _realm = realm; }
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; }
// 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
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);
@ -634,7 +643,7 @@ class LoggingMiddleware : public AsyncMiddleware {
public:
void setOutput(Print& output) { _out = &output; }
void setEnabled(bool enabled) { _enabled = enabled; }
bool isEnabled() { return _enabled && _out; }
bool isEnabled() const { return _enabled && _out; }
void run(AsyncWebServerRequest* request, ArMiddlewareNext next);
@ -722,18 +731,16 @@ class AsyncWebHandler : public AsyncMiddlewareChain {
public:
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 bool canHandle(AsyncWebServerRequest* request __attribute__((unused))) {
return false;
}
AsyncWebHandler& setFilter(ArRequestFilterFunction fn);
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 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 bool isRequestHandlerTrivial() { return true; }
virtual bool isRequestHandlerTrivial() const { return true; }
};
/*
@ -764,26 +771,22 @@ class AsyncWebServerResponse {
WebResponseState _state;
public:
#ifndef ESP8266
static const char* responseCodeToString(int code);
#else
static const __FlashStringHelper* responseCodeToString(int code);
#endif
public:
AsyncWebServerResponse();
virtual ~AsyncWebServerResponse();
virtual void setCode(int code);
virtual ~AsyncWebServerResponse() {}
void setCode(int 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()); }
virtual void setContentType(const char* type);
virtual bool addHeader(const char* name, const char* value, bool replaceExisting = true);
void setContentType(const char* type);
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 const AsyncWebHeader* getHeader(const char* name) const;
bool removeHeader(const char* name);
const AsyncWebHeader* getHeader(const char* name) const;
const std::list<AsyncWebHeader>& getHeaders() const { return _headers; }
#ifndef ESP8266
@ -794,7 +797,7 @@ class AsyncWebServerResponse {
_assembleHead(buffer, version);
return buffer;
}
virtual void _assembleHead(String& buffer, uint8_t version);
void _assembleHead(String& buffer, uint8_t version);
virtual bool _started() const;
virtual bool _finished() const;

View File

@ -66,7 +66,7 @@ void AuthenticationMiddleware::setPassword(const char* password) {
void AuthenticationMiddleware::setPasswordHash(const char* hash) {
_credentials = hash;
_hash = true;
_hash = _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)
return true;
if (!_hasCreds)
if (_authMethod == AsyncAuthType::AUTH_DENIED)
return false;
if (!_hasCreds)
return true;
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) {
response->addHeader(F("Access-Control-Allow-Origin"), _origin.c_str());
response->addHeader(F("Access-Control-Allow-Methods"), _methods.c_str());
response->addHeader(F("Access-Control-Allow-Headers"), _headers.c_str());
response->addHeader(F("Access-Control-Allow-Credentials"), _credentials ? F("true") : F("false"));
response->addHeader(F("Access-Control-Max-Age"), String(_maxAge).c_str());
response->addHeader(asyncsrv::T_CORS_ACAO, _origin.c_str());
response->addHeader(asyncsrv::T_CORS_ACAM, _methods.c_str());
response->addHeader(asyncsrv::T_CORS_ACAH, _headers.c_str());
response->addHeader(asyncsrv::T_CORS_ACAC, _credentials ? asyncsrv::T_TRUE : asyncsrv::T_FALSE);
response->addHeader(asyncsrv::T_CORS_ACMA, String(_maxAge).c_str());
}
void CorsMiddleware::run(AsyncWebServerRequest* request, ArMiddlewareNext next) {
// 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
if (request->method() == HTTP_OPTIONS) {
AsyncWebServerResponse* response = request->beginResponse(200);
@ -247,7 +250,7 @@ void RateLimitMiddleware::run(AsyncWebServerRequest* request, ArMiddlewareNext n
next();
} else {
AsyncWebServerResponse* response = request->beginResponse(429);
response->addHeader(F("Retry-After"), retryAfterSeconds);
response->addHeader(asyncsrv::T_retry_after, retryAfterSeconds);
request->send(response);
}
}

View File

@ -137,11 +137,7 @@ String generateDigestHash(const char* username, const char* password, const char
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)
#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) {
// os_printf("AUTH FAIL: missing requred fields\n");

View File

@ -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);
#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
String generateDigestHash(const char* username, const char* password, const char* realm);

View File

@ -34,8 +34,8 @@ class AsyncStaticWebHandler : public AsyncWebHandler {
using FS = fs::FS;
private:
bool _getFile(AsyncWebServerRequest* request);
bool _fileExists(AsyncWebServerRequest* request, const String& path);
bool _getFile(AsyncWebServerRequest* request) const;
bool _searchFile(AsyncWebServerRequest* request, const String& path);
uint8_t _countBits(const uint8_t value) const;
protected:
@ -47,13 +47,13 @@ class AsyncStaticWebHandler : public AsyncWebHandler {
String _last_modified;
AwsTemplateProcessor _callback;
bool _isDir;
bool _gzipFirst;
uint8_t _gzipStats;
bool _tryGzipFirst = true;
public:
AsyncStaticWebHandler(const char* uri, FS& fs, const char* path, const char* cache_control);
virtual bool canHandle(AsyncWebServerRequest* request) override final;
virtual void handleRequest(AsyncWebServerRequest* request) override final;
bool canHandle(AsyncWebServerRequest* request) const override final;
void handleRequest(AsyncWebServerRequest* request) override final;
AsyncStaticWebHandler& setTryGzipFirst(bool value);
AsyncStaticWebHandler& setIsDir(bool isDir);
AsyncStaticWebHandler& setDefaultFile(const char* filename);
AsyncStaticWebHandler& setCacheControl(const char* cache_control);
@ -84,11 +84,11 @@ class AsyncCallbackWebHandler : public AsyncWebHandler {
void onUpload(ArUploadHandlerFunction fn) { _onUpload = fn; }
void onBody(ArBodyHandlerFunction fn) { _onBody = fn; }
virtual bool canHandle(AsyncWebServerRequest* request) override final;
virtual 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;
virtual 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 canHandle(AsyncWebServerRequest* request) const override final;
void handleRequest(AsyncWebServerRequest* request) override final;
void handleUpload(AsyncWebServerRequest* request, const String& filename, size_t index, uint8_t* data, size_t len, bool final) override final;
void handleBody(AsyncWebServerRequest* request, uint8_t* data, size_t len, size_t index, size_t total) override final;
bool isRequestHandlerTrivial() const override final { return !_onRequest; }
};
#endif /* ASYNCWEBSERVERHANDLERIMPL_H_ */

View File

@ -27,7 +27,7 @@ AsyncWebHandler& AsyncWebHandler::setFilter(ArRequestFilterFunction fn) {
_filter = fn;
return *this;
}
AsyncWebHandler& AsyncWebHandler::setAuthentication(const char* username, const char* password) {
AsyncWebHandler& AsyncWebHandler::setAuthentication(const char* username, const char* password, AsyncAuthType authMethod) {
if (!_authMiddleware) {
_authMiddleware = new AuthenticationMiddleware();
_authMiddleware->_freeOnRemoval = true;
@ -35,6 +35,7 @@ AsyncWebHandler& AsyncWebHandler::setAuthentication(const char* username, const
}
_authMiddleware->setUsername(username);
_authMiddleware->setPassword(password);
_authMiddleware->setAuthType(authMethod);
return *this;
};
@ -56,10 +57,11 @@ AsyncStaticWebHandler::AsyncStaticWebHandler(const char* uri, FS& fs, const char
_uri = _uri.substring(0, _uri.length() - 1);
if (_path[_path.length() - 1] == '/')
_path = _path.substring(0, _path.length() - 1);
}
// Reset stats
_gzipFirst = false;
_gzipStats = 0xF8;
AsyncStaticWebHandler& AsyncStaticWebHandler::setTryGzipFirst(bool value) {
_tryGzipFirst = value;
return *this;
}
AsyncStaticWebHandler& AsyncStaticWebHandler::setIsDir(bool isDir) {
@ -104,14 +106,11 @@ AsyncStaticWebHandler& AsyncStaticWebHandler::setLastModified() {
return setLastModified(last_modified);
}
#endif
bool AsyncStaticWebHandler::canHandle(AsyncWebServerRequest* request) {
if (request->method() != HTTP_GET || !request->url().startsWith(_uri) || !request->isExpectedRequestedConnType(RCT_DEFAULT, RCT_HTTP)) {
return false;
}
return _getFile(request);
bool AsyncStaticWebHandler::canHandle(AsyncWebServerRequest* request) const {
return request->isHTTP() && request->method() == HTTP_GET && request->url().startsWith(_uri) && _getFile(request);
}
bool AsyncStaticWebHandler::_getFile(AsyncWebServerRequest* request) {
bool AsyncStaticWebHandler::_getFile(AsyncWebServerRequest* request) const {
// Remove the found uri
String path = request->url().substring(_uri.length());
@ -121,7 +120,7 @@ bool AsyncStaticWebHandler::_getFile(AsyncWebServerRequest* request) {
path = _path + path;
// Do we have a file or .gz file
if (!canSkipFileCheck && _fileExists(request, path))
if (!canSkipFileCheck && const_cast<AsyncStaticWebHandler*>(this)->_searchFile(request, path))
return true;
// Can't handle if not default file
@ -133,7 +132,7 @@ bool AsyncStaticWebHandler::_getFile(AsyncWebServerRequest* request) {
path += String('/');
path += _default_file;
return _fileExists(request, path);
return const_cast<AsyncStaticWebHandler*>(this)->_searchFile(request, path);
}
#ifdef ESP32
@ -142,13 +141,13 @@ bool AsyncStaticWebHandler::_getFile(AsyncWebServerRequest* request) {
#define FILE_IS_REAL(f) (f == true)
#endif
bool AsyncStaticWebHandler::_fileExists(AsyncWebServerRequest* request, const String& path) {
bool AsyncStaticWebHandler::_searchFile(AsyncWebServerRequest* request, const String& path) {
bool fileFound = false;
bool gzipFound = false;
String gzip = path + F(".gz");
String gzip = path + T__gz;
if (_gzipFirst) {
if (_tryGzipFirst) {
if (_fs.exists(gzip)) {
request->_tempFile = _fs.open(gzip, fs::FileOpenMode::read);
gzipFound = FILE_IS_REAL(request->_tempFile);
@ -180,15 +179,6 @@ bool AsyncStaticWebHandler::_fileExists(AsyncWebServerRequest* request, const St
char* _tempPath = (char*)malloc(pathLen + 1);
snprintf_P(_tempPath, pathLen + 1, PSTR("%s"), path.c_str());
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;
@ -260,11 +250,8 @@ void AsyncCallbackWebHandler::setUri(const String& uri) {
_isRegex = uri.startsWith("^") && uri.endsWith("$");
}
bool AsyncCallbackWebHandler::canHandle(AsyncWebServerRequest* request) {
if (!_onRequest)
return false;
if (!(_method & request->method()))
bool AsyncCallbackWebHandler::canHandle(AsyncWebServerRequest* request) const {
if (!_onRequest || !request->isHTTP() || !(_method & request->method()))
return false;
#ifdef ASYNCWEBSERVER_REGEX

View File

@ -49,9 +49,9 @@ AsyncWebServerRequest::~AsyncWebServerRequest() {
_pathParams.clear();
if (_response != NULL) {
delete _response;
}
AsyncWebServerResponse* r = _response;
_response = NULL;
delete r;
if (_tempObject != NULL) {
free(_tempObject);
@ -280,38 +280,40 @@ bool AsyncWebServerRequest::_parseReqHeader() {
}
} else if (name.equalsIgnoreCase(T_Content_Length)) {
_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;
} else if (name.equalsIgnoreCase(T_AUTH)) {
if (value.length() > 5 && value.substring(0, 5).equalsIgnoreCase(T_BASIC)) {
_authorization = value.substring(6);
_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 {
int space = value.indexOf(' ');
if (space == -1) {
_authorization = value;
_authMethod = AsyncAuthType::AUTH_OTHER;
}
} else {
if (name.equalsIgnoreCase(T_UPGRADE) && value.equalsIgnoreCase(T_WS)) {
// WebSocket request can be uniquely identified by header: [Upgrade: websocket]
_reqconntype = RCT_WS;
} else if (name.equalsIgnoreCase(T_ACCEPT)) {
String lowcase(value);
lowcase.toLowerCase();
#ifndef ESP8266
const char* substr = std::strstr(lowcase.c_str(), T_text_event_stream);
#else
const char* substr = std::strstr(lowcase.c_str(), String(T_text_event_stream).c_str());
#endif
if (substr != NULL) {
// WebEvent request can be uniquely identified by header: [Accept: text/event-stream]
_reqconntype = RCT_EVENT;
} else {
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]
_reqconntype = RCT_WS;
} else if (name.equalsIgnoreCase(T_ACCEPT)) {
String lowcase(value);
lowcase.toLowerCase();
#ifndef ESP8266
const char* substr = std::strstr(lowcase.c_str(), T_text_event_stream);
#else
const char* substr = std::strstr(lowcase.c_str(), String(T_text_event_stream).c_str());
#endif
if (substr != NULL) {
// WebEvent request can be uniquely identified by header: [Accept: text/event-stream]
_reqconntype = RCT_EVENT;
}
}
_headers.emplace_back(name, value);
@ -779,7 +781,7 @@ void AsyncWebServerRequest::redirect(const char* url, int code) {
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 (_authMethod == AsyncAuthType::AUTH_DIGEST)
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;
}
bool AsyncWebServerRequest::authenticate(const char* hash) {
bool AsyncWebServerRequest::authenticate(const char* hash) const {
if (!_authorization.length() || hash == NULL)
return false;
@ -831,7 +833,7 @@ void AsyncWebServerRequest::requestAuthentication(AsyncAuthType method, const ch
break;
}
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;
header.reserve(len + strlen(realm));
header.concat(T_DIGEST_);
@ -938,7 +940,6 @@ String AsyncWebServerRequest::urlDecode(const String& text) const {
return decoded;
}
#ifndef ESP8266
const char* AsyncWebServerRequest::methodToString() const {
if (_method == HTTP_ANY)
return T_ANY;
@ -958,29 +959,7 @@ const char* AsyncWebServerRequest::methodToString() const {
return T_OPTIONS;
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 {
switch (_reqconntype) {
case RCT_NOT_USED:
@ -997,32 +976,9 @@ const char* AsyncWebServerRequest::requestedConnTypeToString() const {
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 res = false;
if ((erct1 != RCT_NOT_USED) && (erct1 == _reqconntype))
res = true;
if ((erct2 != RCT_NOT_USED) && (erct2 == _reqconntype))
res = true;
if ((erct3 != RCT_NOT_USED) && (erct3 == _reqconntype))
res = true;
return res;
bool AsyncWebServerRequest::isExpectedRequestedConnType(RequestedConnectionType erct1, RequestedConnectionType erct2, RequestedConnectionType erct3) const {
return ((erct1 != RCT_NOT_USED) && (erct1 == _reqconntype)) ||
((erct2 != RCT_NOT_USED) && (erct2 == _reqconntype)) ||
((erct3 != RCT_NOT_USED) && (erct3 == _reqconntype));
}

View File

@ -26,9 +26,10 @@
#undef min
#undef max
#endif
#include "literals.h"
#include <StreamString.h>
#include <memory>
#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.
@ -39,9 +40,9 @@ class AsyncBasicResponse : public AsyncWebServerResponse {
public:
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()) {}
void _respond(AsyncWebServerRequest* request);
size_t _ack(AsyncWebServerRequest* request, size_t len, uint32_t time);
bool _sourceValid() const { return true; }
void _respond(AsyncWebServerRequest* request) override final;
size_t _ack(AsyncWebServerRequest* request, size_t len, uint32_t time) override final;
bool _sourceValid() const override final { return true; }
};
class AsyncAbstractResponse : public AsyncWebServerResponse {
@ -60,9 +61,10 @@ class AsyncAbstractResponse : public AsyncWebServerResponse {
public:
AsyncAbstractResponse(AwsTemplateProcessor callback = nullptr);
void _respond(AsyncWebServerRequest* request);
size_t _ack(AsyncWebServerRequest* request, size_t len, uint32_t time);
bool _sourceValid() const { return false; }
virtual ~AsyncAbstractResponse() {}
void _respond(AsyncWebServerRequest* request) override final;
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; }
};
@ -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(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();
bool _sourceValid() const { return !!(_content); }
virtual size_t _fillBuffer(uint8_t* buf, size_t maxLen) override;
~AsyncFileResponse() { _content.close(); }
bool _sourceValid() const override final { return !!(_content); }
size_t _fillBuffer(uint8_t* buf, size_t maxLen) override final;
};
class AsyncStreamResponse : public AsyncAbstractResponse {
@ -97,8 +99,8 @@ class AsyncStreamResponse : public AsyncAbstractResponse {
public:
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) {}
bool _sourceValid() const { return !!(_content); }
virtual size_t _fillBuffer(uint8_t* buf, size_t maxLen) override;
bool _sourceValid() const override final { return !!(_content); }
size_t _fillBuffer(uint8_t* buf, size_t maxLen) override final;
};
class AsyncCallbackResponse : public AsyncAbstractResponse {
@ -109,8 +111,8 @@ class AsyncCallbackResponse : public AsyncAbstractResponse {
public:
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) {}
bool _sourceValid() const { return !!(_content); }
virtual size_t _fillBuffer(uint8_t* buf, size_t maxLen) override;
bool _sourceValid() const override final { return !!(_content); }
size_t _fillBuffer(uint8_t* buf, size_t maxLen) override final;
};
class AsyncChunkedResponse : public AsyncAbstractResponse {
@ -121,8 +123,8 @@ class AsyncChunkedResponse : public AsyncAbstractResponse {
public:
AsyncChunkedResponse(const char* contentType, AwsResponseFiller callback, AwsTemplateProcessor templateCallback = nullptr);
AsyncChunkedResponse(const String& contentType, AwsResponseFiller callback, AwsTemplateProcessor templateCallback = nullptr) : AsyncChunkedResponse(contentType.c_str(), callback, templateCallback) {}
bool _sourceValid() const { return !!(_content); }
virtual size_t _fillBuffer(uint8_t* buf, size_t maxLen) override;
bool _sourceValid() const override final { return !!(_content); }
size_t _fillBuffer(uint8_t* buf, size_t maxLen) override final;
};
class AsyncProgmemResponse : public AsyncAbstractResponse {
@ -133,22 +135,19 @@ class AsyncProgmemResponse : public AsyncAbstractResponse {
public:
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) {}
bool _sourceValid() const { return true; }
virtual size_t _fillBuffer(uint8_t* buf, size_t maxLen) override;
bool _sourceValid() const override final { return true; }
size_t _fillBuffer(uint8_t* buf, size_t maxLen) override final;
};
class cbuf;
class AsyncResponseStream : public AsyncAbstractResponse, public Print {
private:
std::unique_ptr<cbuf> _content;
StreamString _content;
public:
AsyncResponseStream(const char* contentType, size_t bufferSize);
AsyncResponseStream(const String& contentType, size_t bufferSize) : AsyncResponseStream(contentType.c_str(), bufferSize) {}
~AsyncResponseStream();
bool _sourceValid() const { return (_state < RESPONSE_END); }
virtual size_t _fillBuffer(uint8_t* buf, size_t maxLen) override;
bool _sourceValid() const override final { return (_state < RESPONSE_END); }
size_t _fillBuffer(uint8_t* buf, size_t maxLen) override final;
size_t write(const uint8_t* data, size_t len);
size_t write(uint8_t data);
using Print::write;

View File

@ -20,7 +20,6 @@
*/
#include "ESPAsyncWebServer.h"
#include "WebResponseImpl.h"
#include "cbuf.h"
using namespace asyncsrv;
@ -38,7 +37,6 @@ void* memchr(void* ptr, int ch, size_t count) {
*
*/
#ifndef ESP8266
const char* AsyncWebServerResponse::responseCodeToString(int code) {
switch (code) {
case 100:
@ -127,96 +125,6 @@ const char* AsyncWebServerResponse::responseCodeToString(int code) {
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()
: _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) {
if (_state == RESPONSE_SETUP)
_code = code;
@ -648,11 +554,6 @@ size_t AsyncAbstractResponse::_fillBufferAndProcessTemplates(uint8_t* data, size
* File Response
* */
AsyncFileResponse::~AsyncFileResponse() {
if (_content)
_content.close();
}
void AsyncFileResponse::_setContentTypeFromPath(const String& path) {
#if HAVE_EXTERN_GET_Content_Type_FUNCTION
#ifndef ESP8266
@ -868,24 +769,17 @@ AsyncResponseStream::AsyncResponseStream(const char* contentType, size_t bufferS
_code = 200;
_contentLength = 0;
_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) {
return _content->read((char*)buf, maxLen);
return _content.readBytes((char*)buf, maxLen);
}
size_t AsyncResponseStream::write(const uint8_t* data, size_t len) {
if (_started())
return 0;
if (len > _content->room()) {
size_t needed = len - _content->room();
_content->resizeAdd(needed);
}
size_t written = _content->write((const char*)data, len);
size_t written = _content.write(data, len);
_contentLength += written;
return written;
}

View File

@ -2,346 +2,181 @@
namespace asyncsrv {
static constexpr const char* empty = "";
static constexpr const char* empty = "";
#ifndef ESP8622
static constexpr const char* T_100_CONTINUE = "100-continue";
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_AUTH = "Authorization";
static constexpr const char* T_BASIC = "Basic";
static constexpr const char* T_BASIC_REALM = "Basic realm=\"";
static constexpr const char* T_LOGIN_REQ = "Login Required";
static constexpr const char* T_BODY = "body";
static constexpr const char* T_Cache_Control = "Cache-Control";
static constexpr const char* T_chunked = "chunked";
static constexpr const char* T_close = "close";
static constexpr const char* T_Connection = "Connection";
static constexpr const char* T_Content_Disposition = "Content-Disposition";
static constexpr const char* T_Content_Encoding = "Content-Encoding";
static constexpr const char* T_Content_Length = "Content-Length";
static constexpr const char* T_Content_Type = "Content-Type";
static constexpr const char* T_Cookie = "Cookie";
static constexpr const char* T_DIGEST = "Digest";
static constexpr const char* T_DIGEST_ = "Digest ";
static constexpr const char* T_BEARER = "Bearer";
static constexpr const char* T_ETag = "ETag";
static constexpr const char* T_EXPECT = "Expect";
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_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_Last_Event_ID = "Last-Event-ID";
static constexpr const char* T_Last_Modified = "Last-Modified";
static constexpr const char* T_LOCATION = "Location";
static constexpr const char* T_MULTIPART_ = "multipart/";
static constexpr const char* T_no_cache = "no-cache";
static constexpr const char* T_none = "none";
static constexpr const char* T_UPGRADE = "Upgrade";
static constexpr const char* T_WS = "websocket";
static constexpr const char* T_WWW_AUTH = "WWW-Authenticate";
static constexpr const char* T_Transfer_Encoding = "Transfer-Encoding";
static constexpr const char* T__opaque = "\", opaque=\"";
static constexpr const char* T_100_CONTINUE = "100-continue";
static constexpr const char* T_13 = "13";
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_AUTH = "authorization";
static constexpr const char* T_auth_nonce = "\", qop=\"auth\", nonce=\"";
static constexpr const char* T_BASIC = "basic";
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_Cache_Control = "cache-control";
static constexpr const char* T_chunked = "chunked";
static constexpr const char* T_close = "close";
static constexpr const char* T_cnonce = "cnonce";
static constexpr const char* T_Connection = "connection";
static constexpr const char* T_Content_Disposition = "content-disposition";
static constexpr const char* T_Content_Encoding = "content-encoding";
static constexpr const char* T_Content_Length = "content-length";
static constexpr const char* T_Content_Type = "content-type";
static constexpr const char* T_Cookie = "cookie";
static constexpr const char* T_CORS_ACAC = "access-control-allow-credentials";
static constexpr const char* T_CORS_ACAH = "access-control-allow-headers";
static constexpr const char* T_CORS_ACAM = "access-control-allow-methods";
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_100_CONT = "HTTP/1.1 100 Continue\r\n\r\n";
static constexpr const char* T_id__ = "id: ";
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_Last_Event_ID = "last-event-id";
static constexpr const char* T_Last_Modified = "last-modified";
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_name = "name";
static constexpr const char* T_nc = "nc";
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_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_WWW_AUTH = "www-authenticate";
// HTTP Methods
static constexpr const char* T_ANY = "ANY";
static constexpr const char* T_GET = "GET";
static constexpr const char* T_POST = "POST";
static constexpr const char* T_PUT = "PUT";
static constexpr const char* T_DELETE = "DELETE";
static constexpr const char* T_PATCH = "PATCH";
static constexpr const char* T_HEAD = "HEAD";
static constexpr const char* T_OPTIONS = "OPTIONS";
static constexpr const char* T_UNKNOWN = "UNKNOWN";
// HTTP Methods
// Req content types
static constexpr const char* T_RCT_NOT_USED = "RCT_NOT_USED";
static constexpr const char* T_RCT_DEFAULT = "RCT_DEFAULT";
static constexpr const char* T_RCT_HTTP = "RCT_HTTP";
static constexpr const char* T_RCT_WS = "RCT_WS";
static constexpr const char* T_RCT_EVENT = "RCT_EVENT";
static constexpr const char* T_ERROR = "ERROR";
static constexpr const char* T_ANY = "ANY";
static constexpr const char* T_GET = "GET";
static constexpr const char* T_POST = "POST";
static constexpr const char* T_PUT = "PUT";
static constexpr const char* T_DELETE = "DELETE";
static constexpr const char* T_PATCH = "PATCH";
static constexpr const char* T_HEAD = "HEAD";
static constexpr const char* T_OPTIONS = "OPTIONS";
static constexpr const char* T_UNKNOWN = "UNKNOWN";
// extentions & MIME-Types
static constexpr const char* T__css = ".css";
static constexpr const char* T__eot = ".eot";
static constexpr const char* T__gif = ".gif";
static constexpr const char* T__gz = ".gz";
static constexpr const char* T__htm = ".htm";
static constexpr const char* T__html = ".html";
static constexpr const char* T__ico = ".ico";
static constexpr const char* T__jpg = ".jpg";
static constexpr const char* T__js = ".js";
static constexpr const char* T__json = ".json";
static constexpr const char* T__pdf = ".pdf";
static constexpr const char* T__png = ".png";
static constexpr const char* T__svg = ".svg";
static constexpr const char* T__ttf = ".ttf";
static constexpr const char* T__woff = ".woff";
static constexpr const char* T__woff2 = ".woff2";
static constexpr const char* T__xml = ".xml";
static constexpr const char* T__zip = ".zip";
static constexpr const char* T_application_javascript = "application/javascript";
static constexpr const char* T_application_json = "application/json";
static constexpr const char* T_application_msgpack = "application/msgpack";
static constexpr const char* T_application_pdf = "application/pdf";
static constexpr const char* T_application_x_gzip = "application/x-gzip";
static constexpr const char* T_application_zip = "application/zip";
static constexpr const char* T_font_eot = "font/eot";
static constexpr const char* T_font_ttf = "font/ttf";
static constexpr const char* T_font_woff = "font/woff";
static constexpr const char* T_font_woff2 = "font/woff2";
static constexpr const char* T_image_gif = "image/gif";
static constexpr const char* T_image_jpeg = "image/jpeg";
static constexpr const char* T_image_png = "image/png";
static constexpr const char* T_image_svg_xml = "image/svg+xml";
static constexpr const char* T_image_x_icon = "image/x-icon";
static constexpr const char* T_text_css = "text/css";
static constexpr const char* T_text_event_stream = "text/event-stream";
static constexpr const char* T_text_html = "text/html";
static constexpr const char* T_text_plain = "text/plain";
static constexpr const char* T_text_xml = "text/xml";
// Req content types
static constexpr const char* T_RCT_NOT_USED = "RCT_NOT_USED";
static constexpr const char* T_RCT_DEFAULT = "RCT_DEFAULT";
static constexpr const char* T_RCT_HTTP = "RCT_HTTP";
static constexpr const char* T_RCT_WS = "RCT_WS";
static constexpr const char* T_RCT_EVENT = "RCT_EVENT";
static constexpr const char* T_ERROR = "ERROR";
// Responce codes
static constexpr const char* T_HTTP_CODE_100 = "Continue";
static constexpr const char* T_HTTP_CODE_101 = "Switching Protocols";
static constexpr const char* T_HTTP_CODE_200 = "OK";
static constexpr const char* T_HTTP_CODE_201 = "Created";
static constexpr const char* T_HTTP_CODE_202 = "Accepted";
static constexpr const char* T_HTTP_CODE_203 = "Non-Authoritative Information";
static constexpr const char* T_HTTP_CODE_204 = "No Content";
static constexpr const char* T_HTTP_CODE_205 = "Reset Content";
static constexpr const char* T_HTTP_CODE_206 = "Partial Content";
static constexpr const char* T_HTTP_CODE_300 = "Multiple Choices";
static constexpr const char* T_HTTP_CODE_301 = "Moved Permanently";
static constexpr const char* T_HTTP_CODE_302 = "Found";
static constexpr const char* T_HTTP_CODE_303 = "See Other";
static constexpr const char* T_HTTP_CODE_304 = "Not Modified";
static constexpr const char* T_HTTP_CODE_305 = "Use Proxy";
static constexpr const char* T_HTTP_CODE_307 = "Temporary Redirect";
static constexpr const char* T_HTTP_CODE_400 = "Bad Request";
static constexpr const char* T_HTTP_CODE_401 = "Unauthorized";
static constexpr const char* T_HTTP_CODE_402 = "Payment Required";
static constexpr const char* T_HTTP_CODE_403 = "Forbidden";
static constexpr const char* T_HTTP_CODE_404 = "Not Found";
static constexpr const char* T_HTTP_CODE_405 = "Method Not Allowed";
static constexpr const char* T_HTTP_CODE_406 = "Not Acceptable";
static constexpr const char* T_HTTP_CODE_407 = "Proxy Authentication Required";
static constexpr const char* T_HTTP_CODE_408 = "Request Time-out";
static constexpr const char* T_HTTP_CODE_409 = "Conflict";
static constexpr const char* T_HTTP_CODE_410 = "Gone";
static constexpr const char* T_HTTP_CODE_411 = "Length Required";
static constexpr const char* T_HTTP_CODE_412 = "Precondition Failed";
static constexpr const char* T_HTTP_CODE_413 = "Request Entity Too Large";
static constexpr const char* T_HTTP_CODE_414 = "Request-URI Too Large";
static constexpr const char* T_HTTP_CODE_415 = "Unsupported Media Type";
static constexpr const char* T_HTTP_CODE_416 = "Requested range not satisfiable";
static constexpr const char* T_HTTP_CODE_417 = "Expectation Failed";
static constexpr const char* T_HTTP_CODE_429 = "Too Many Requests";
static constexpr const char* T_HTTP_CODE_500 = "Internal Server Error";
static constexpr const char* T_HTTP_CODE_501 = "Not Implemented";
static constexpr const char* T_HTTP_CODE_502 = "Bad Gateway";
static constexpr const char* T_HTTP_CODE_503 = "Service Unavailable";
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_ANY = "Unknown code";
// extentions & MIME-Types
static constexpr const char* T__css = ".css";
static constexpr const char* T__eot = ".eot";
static constexpr const char* T__gif = ".gif";
static constexpr const char* T__gz = ".gz";
static constexpr const char* T__htm = ".htm";
static constexpr const char* T__html = ".html";
static constexpr const char* T__ico = ".ico";
static constexpr const char* T__jpg = ".jpg";
static constexpr const char* T__js = ".js";
static constexpr const char* T__json = ".json";
static constexpr const char* T__pdf = ".pdf";
static constexpr const char* T__png = ".png";
static constexpr const char* T__svg = ".svg";
static constexpr const char* T__ttf = ".ttf";
static constexpr const char* T__woff = ".woff";
static constexpr const char* T__woff2 = ".woff2";
static constexpr const char* T__xml = ".xml";
static constexpr const char* T__zip = ".zip";
static constexpr const char* T_application_javascript = "application/javascript";
static constexpr const char* T_application_json = "application/json";
static constexpr const char* T_application_msgpack = "application/msgpack";
static constexpr const char* T_application_pdf = "application/pdf";
static constexpr const char* T_application_x_gzip = "application/x-gzip";
static constexpr const char* T_application_zip = "application/zip";
static constexpr const char* T_font_eot = "font/eot";
static constexpr const char* T_font_ttf = "font/ttf";
static constexpr const char* T_font_woff = "font/woff";
static constexpr const char* T_font_woff2 = "font/woff2";
static constexpr const char* T_image_gif = "image/gif";
static constexpr const char* T_image_jpeg = "image/jpeg";
static constexpr const char* T_image_png = "image/png";
static constexpr const char* T_image_svg_xml = "image/svg+xml";
static constexpr const char* T_image_x_icon = "image/x-icon";
static constexpr const char* T_text_css = "text/css";
static constexpr const char* T_text_event_stream = "text/event-stream";
static constexpr const char* T_text_html = "text/html";
static constexpr const char* T_text_plain = "text/plain";
static constexpr const char* T_text_xml = "text/xml";
// 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";
// Responce codes
static constexpr const char* T_HTTP_CODE_100 = "Continue";
static constexpr const char* T_HTTP_CODE_101 = "Switching Protocols";
static constexpr const char* T_HTTP_CODE_200 = "OK";
static constexpr const char* T_HTTP_CODE_201 = "Created";
static constexpr const char* T_HTTP_CODE_202 = "Accepted";
static constexpr const char* T_HTTP_CODE_203 = "Non-Authoritative Information";
static constexpr const char* T_HTTP_CODE_204 = "No Content";
static constexpr const char* T_HTTP_CODE_205 = "Reset Content";
static constexpr const char* T_HTTP_CODE_206 = "Partial Content";
static constexpr const char* T_HTTP_CODE_300 = "Multiple Choices";
static constexpr const char* T_HTTP_CODE_301 = "Moved Permanently";
static constexpr const char* T_HTTP_CODE_302 = "Found";
static constexpr const char* T_HTTP_CODE_303 = "See Other";
static constexpr const char* T_HTTP_CODE_304 = "Not Modified";
static constexpr const char* T_HTTP_CODE_305 = "Use Proxy";
static constexpr const char* T_HTTP_CODE_307 = "Temporary Redirect";
static constexpr const char* T_HTTP_CODE_400 = "Bad Request";
static constexpr const char* T_HTTP_CODE_401 = "Unauthorized";
static constexpr const char* T_HTTP_CODE_402 = "Payment Required";
static constexpr const char* T_HTTP_CODE_403 = "Forbidden";
static constexpr const char* T_HTTP_CODE_404 = "Not Found";
static constexpr const char* T_HTTP_CODE_405 = "Method Not Allowed";
static constexpr const char* T_HTTP_CODE_406 = "Not Acceptable";
static constexpr const char* T_HTTP_CODE_407 = "Proxy Authentication Required";
static constexpr const char* T_HTTP_CODE_408 = "Request Time-out";
static constexpr const char* T_HTTP_CODE_409 = "Conflict";
static constexpr const char* T_HTTP_CODE_410 = "Gone";
static constexpr const char* T_HTTP_CODE_411 = "Length Required";
static constexpr const char* T_HTTP_CODE_412 = "Precondition Failed";
static constexpr const char* T_HTTP_CODE_413 = "Request Entity Too Large";
static constexpr const char* T_HTTP_CODE_414 = "Request-URI Too Large";
static constexpr const char* T_HTTP_CODE_415 = "Unsupported Media Type";
static constexpr const char* T_HTTP_CODE_416 = "Requested range not satisfiable";
static constexpr const char* T_HTTP_CODE_417 = "Expectation Failed";
static constexpr const char* T_HTTP_CODE_429 = "Too Many Requests";
static constexpr const char* T_HTTP_CODE_500 = "Internal Server Error";
static constexpr const char* T_HTTP_CODE_501 = "Not Implemented";
static constexpr const char* T_HTTP_CODE_502 = "Bad Gateway";
static constexpr const char* T_HTTP_CODE_503 = "Service Unavailable";
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_ANY = "Unknown code";
#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 {}