1 Commits

Author SHA1 Message Date
76648f4c2d Posledni verze se zmenami Lorola i Pangolina 2021-06-24 17:37:53 +02:00
13 changed files with 1201 additions and 1051 deletions

View File

@ -18,15 +18,11 @@
"platforms": ["espressif8266", "espressif32"], "platforms": ["espressif8266", "espressif32"],
"dependencies": [ "dependencies": [
{ {
"owner": "me-no-dev",
"name": "ESPAsyncTCP", "name": "ESPAsyncTCP",
"version": "^1.2.2",
"platforms": "espressif8266" "platforms": "espressif8266"
}, },
{ {
"owner": "me-no-dev",
"name": "AsyncTCP", "name": "AsyncTCP",
"version": "^1.1.1",
"platforms": "espressif32" "platforms": "espressif32"
}, },
{ {

View File

@ -21,7 +21,7 @@
#include "AsyncEventSource.h" #include "AsyncEventSource.h"
static String generateEventMessage(const char *message, const char *event, uint32_t id, uint32_t reconnect){ static String generateEventMessage(const char *message, const char *event, uint32_t id, uint32_t reconnect){
String ev; String ev = "";
if(reconnect){ if(reconnect){
ev += F("retry: "); ev += F("retry: ");
@ -137,17 +137,16 @@ size_t AsyncEventSourceMessage::ack(size_t len, uint32_t time) {
return 0; return 0;
} }
// This could also return void as the return value is not used.
// Leaving as-is for compatibility...
size_t AsyncEventSourceMessage::send(AsyncClient *client) { size_t AsyncEventSourceMessage::send(AsyncClient *client) {
if (_sent >= _len) { const size_t len = _len - _sent;
if(client->space() < len){
return 0; return 0;
} }
const size_t len_to_send = _len - _sent; size_t sent = client->add((const char *)_data, len);
auto position = reinterpret_cast<const char*>(_data + _sent); if(client->canSend())
const size_t sent_now = client->write(position, len_to_send); client->send();
_sent += sent_now; _sent += sent;
return sent_now; return sent;
} }
// Client // Client
@ -174,9 +173,7 @@ AsyncEventSourceClient::AsyncEventSourceClient(AsyncWebServerRequest *request, A
} }
AsyncEventSourceClient::~AsyncEventSourceClient(){ AsyncEventSourceClient::~AsyncEventSourceClient(){
_lockmq.lock();
_messageQueue.free(); _messageQueue.free();
_lockmq.unlock();
close(); close();
} }
@ -187,43 +184,37 @@ void AsyncEventSourceClient::_queueMessage(AsyncEventSourceMessage *dataMessage)
delete dataMessage; delete dataMessage;
return; return;
} }
//length() is not thread-safe, thus acquiring the lock before this call..
_lockmq.lock();
if(_messageQueue.length() >= SSE_MAX_QUEUED_MESSAGES){ if(_messageQueue.length() >= SSE_MAX_QUEUED_MESSAGES){
ets_printf(String(F("ERROR: Too many messages queued\n")).c_str()); ets_printf(String(F("ERROR: Too many messages queued\n")).c_str());
delete dataMessage; delete dataMessage;
} else { } else {
_messageQueue.add(dataMessage); _messageQueue.add(dataMessage);
// runqueue trigger when new messages added }
if(_client->canSend()) { if(_client->canSend())
_runQueue(); _runQueue();
}
}
_lockmq.unlock();
} }
void AsyncEventSourceClient::_onAck(size_t len, uint32_t time){ void AsyncEventSourceClient::_onAck(size_t len, uint32_t time){
// Same here, acquiring the lock early
_lockmq.lock();
while(len && !_messageQueue.isEmpty()){ while(len && !_messageQueue.isEmpty()){
len = _messageQueue.front()->ack(len, time); len = _messageQueue.front()->ack(len, time);
if(_messageQueue.front()->finished()) if(_messageQueue.front()->finished())
_messageQueue.remove(_messageQueue.front()); _messageQueue.remove(_messageQueue.front());
} }
_runQueue(); _runQueue();
_lockmq.unlock();
} }
void AsyncEventSourceClient::_onPoll(){ void AsyncEventSourceClient::_onPoll(){
_lockmq.lock();
if(!_messageQueue.isEmpty()){ if(!_messageQueue.isEmpty()){
_runQueue(); _runQueue();
} }
_lockmq.unlock();
} }
void AsyncEventSourceClient::_onTimeout(uint32_t time __attribute__((unused))){ void AsyncEventSourceClient::_onTimeout(uint32_t time __attribute__((unused))){
_client->close(true); //_client->close(true); according to Pango "Too harsh! breaks webui" so beware...
_messageQueue.remove(_messageQueue.front());
_runQueue();
} }
void AsyncEventSourceClient::_onDisconnect(){ void AsyncEventSourceClient::_onDisconnect(){
@ -236,7 +227,7 @@ void AsyncEventSourceClient::close(){
_client->close(); _client->close();
} }
void AsyncEventSourceClient::_write(const char * message, size_t len){ void AsyncEventSourceClient::write(const char * message, size_t len){
_queueMessage(new AsyncEventSourceMessage(message, len)); _queueMessage(new AsyncEventSourceMessage(message, len));
} }
@ -245,23 +236,15 @@ void AsyncEventSourceClient::send(const char *message, const char *event, uint32
_queueMessage(new AsyncEventSourceMessage(ev.c_str(), ev.length())); _queueMessage(new AsyncEventSourceMessage(ev.c_str(), ev.length()));
} }
size_t AsyncEventSourceClient::packetsWaiting() const { void AsyncEventSourceClient::_runQueue(){
size_t len; while(!_messageQueue.isEmpty() && _messageQueue.front()->finished()){
_lockmq.lock(); _messageQueue.remove(_messageQueue.front());
len = _messageQueue.length();
_lockmq.unlock();
return len;
}
void AsyncEventSourceClient::_runQueue() {
// Calls to this private method now already protected by _lockmq acquisition
// so no extra call of _lockmq.lock() here..
for (auto i = _messageQueue.begin(); i != _messageQueue.end(); ++i) {
// If it crashes here, iterator (i) has been invalidated as _messageQueue
// has been changed... (UL 2020-11-15: Not supposed to happen any more ;-) )
if (!(*i)->sent()) {
(*i)->send(_client);
} }
for(auto i = _messageQueue.begin(); i != _messageQueue.end(); ++i)
{
if(!(*i)->sent())
(*i)->send(_client);
} }
} }
@ -299,22 +282,17 @@ void AsyncEventSource::_addClient(AsyncEventSourceClient * client){
client->write((const char *)temp, 2053); client->write((const char *)temp, 2053);
free(temp); free(temp);
}*/ }*/
AsyncWebLockGuard l(_client_queue_lock);
_clients.add(client); _clients.add(client);
if(_connectcb) if(_connectcb)
_connectcb(client); _connectcb(client);
} }
void AsyncEventSource::_handleDisconnect(AsyncEventSourceClient * client){ void AsyncEventSource::_handleDisconnect(AsyncEventSourceClient * client){
AsyncWebLockGuard l(_client_queue_lock);
_clients.remove(client); _clients.remove(client);
} }
void AsyncEventSource::close(){ void AsyncEventSource::close(){
// While the whole loop is not done, the linked list is locked and so the
// iterator should remain valid even when AsyncEventSource::_handleDisconnect()
// is called very early
AsyncWebLockGuard l(_client_queue_lock);
for(const auto &c: _clients){ for(const auto &c: _clients){
if(c->connected()) if(c->connected())
c->close(); c->close();
@ -323,39 +301,37 @@ void AsyncEventSource::close(){
// pmb fix // pmb fix
size_t AsyncEventSource::avgPacketsWaiting() const { size_t AsyncEventSource::avgPacketsWaiting() const {
size_t aql = 0; if(_clients.isEmpty())
uint32_t nConnectedClients = 0;
AsyncWebLockGuard l(_client_queue_lock);
if (_clients.isEmpty()) {
return 0; return 0;
}
size_t aql=0;
uint32_t nConnectedClients=0;
for(const auto &c: _clients){ for(const auto &c: _clients){
if(c->connected()) { if(c->connected()) {
aql += c->packetsWaiting(); aql+=c->packetsWaiting();
++nConnectedClients; ++nConnectedClients;
} }
} }
return ((aql) + (nConnectedClients/2)) / (nConnectedClients); // round up // return aql / nConnectedClients;
return ((aql) + (nConnectedClients/2))/(nConnectedClients); // round up
} }
void AsyncEventSource::send( void AsyncEventSource::send(const char *message, const char *event, uint32_t id, uint32_t reconnect){
const char *message, const char *event, uint32_t id, uint32_t reconnect){
String ev = generateEventMessage(message, event, id, reconnect); String ev = generateEventMessage(message, event, id, reconnect);
AsyncWebLockGuard l(_client_queue_lock);
for(const auto &c: _clients){ for(const auto &c: _clients){
if(c->connected()) { if(c->connected()) {
c->_write(ev.c_str(), ev.length()); c->write(ev.c_str(), ev.length());
} }
} }
} }
size_t AsyncEventSource::count() const { size_t AsyncEventSource::count() const {
size_t n_clients; return _clients.count_if([](AsyncEventSourceClient *c){
AsyncWebLockGuard l(_client_queue_lock);
n_clients = _clients.count_if([](AsyncEventSourceClient *c){
return c->connected(); return c->connected();
}); });
return n_clients;
} }
bool AsyncEventSource::canHandle(AsyncWebServerRequest *request){ bool AsyncEventSource::canHandle(AsyncWebServerRequest *request){

View File

@ -73,8 +73,6 @@ class AsyncEventSourceClient {
AsyncEventSource *_server; AsyncEventSource *_server;
uint32_t _lastId; uint32_t _lastId;
LinkedList<AsyncEventSourceMessage *> _messageQueue; LinkedList<AsyncEventSourceMessage *> _messageQueue;
// ArFi 2020-08-27 for protecting/serializing _messageQueue
AsyncPlainLock _lockmq;
void _queueMessage(AsyncEventSourceMessage *dataMessage); void _queueMessage(AsyncEventSourceMessage *dataMessage);
void _runQueue(); void _runQueue();
@ -85,12 +83,12 @@ class AsyncEventSourceClient {
AsyncClient* client(){ return _client; } AsyncClient* client(){ return _client; }
void close(); void close();
void write(const char * message, size_t len);
void send(const char *message, const char *event=NULL, uint32_t id=0, uint32_t reconnect=0); 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 connected() const { return (_client != NULL) && _client->connected(); }
uint32_t lastId() const { return _lastId; } uint32_t lastId() const { return _lastId; }
size_t packetsWaiting() const; size_t packetsWaiting() const { return _messageQueue.length(); }
void _write(const char * message, size_t len);
//system callbacks (do not call) //system callbacks (do not call)
void _onAck(size_t len, uint32_t time); void _onAck(size_t len, uint32_t time);
void _onPoll(); void _onPoll();
@ -102,9 +100,6 @@ class AsyncEventSource: public AsyncWebHandler {
private: private:
String _url; String _url;
LinkedList<AsyncEventSourceClient *> _clients; LinkedList<AsyncEventSourceClient *> _clients;
// Same as for individual messages, protect mutations of _clients list
// since simultaneous access from different tasks is possible
AsyncWebLock _client_queue_lock;
ArEventHandlerFunction _connectcb; ArEventHandlerFunction _connectcb;
ArAuthorizeConnectHandler _authorizeConnectHandler; ArAuthorizeConnectHandler _authorizeConnectHandler;
public: public:
@ -116,7 +111,7 @@ class AsyncEventSource: public AsyncWebHandler {
void onConnect(ArEventHandlerFunction cb); void onConnect(ArEventHandlerFunction cb);
void authorizeConnect(ArAuthorizeConnectHandler cb); void authorizeConnect(ArAuthorizeConnectHandler cb);
void send(const char *message, const char *event=NULL, uint32_t id=0, uint32_t reconnect=0); void send(const char *message, const char *event=NULL, uint32_t id=0, uint32_t reconnect=0);
size_t count() const; //number clients connected size_t count() const; //number clinets connected
size_t avgPacketsWaiting() const; size_t avgPacketsWaiting() const;
//system callbacks (do not call) //system callbacks (do not call)

File diff suppressed because it is too large Load Diff

View File

@ -23,20 +23,22 @@
#include <Arduino.h> #include <Arduino.h>
#ifdef ESP32 #ifdef ESP32
#include <AsyncTCP.h> # include <AsyncTCP.h>
#define WS_MAX_QUEUED_MESSAGES 16 # if !defined(WS_MAX_QUEUED_MESSAGES) || WS_MAX_QUEUED_MESSAGES < 1
# undef WS_MAX_QUEUED_MESSAGES
# define WS_MAX_QUEUED_MESSAGES 32
# endif // !defined(WS_MAX_QUEUED_MESSAGES) || WS_MAX_QUEUED_MESSAGES < 1
#else #else
#include <ESPAsyncTCP.h> # include <ESPAsyncTCP.h>
#define WS_MAX_QUEUED_MESSAGES 8 # if !defined(WS_MAX_QUEUED_MESSAGES) || WS_MAX_QUEUED_MESSAGES < 1
# undef WS_MAX_QUEUED_MESSAGES
# define WS_MAX_QUEUED_MESSAGES 8
# endif // !defined(WS_MAX_QUEUED_MESSAGES) || WS_MAX_QUEUED_MESSAGES < 1
#endif #endif
#include <ESPAsyncWebServer.h> #include <ESPAsyncWebServer.h>
#include "AsyncWebSynchronization.h" #include "AsyncWebSynchronization.h"
#include <list>
#include <deque>
#include <memory>
#ifdef ESP8266 #ifdef ESP8266
#include <Hash.h> #include <Hash.h>
#ifdef CRYPTO_HASH_h // include Hash.h from espressif framework if the first include was from the crypto library #ifdef CRYPTO_HASH_h // include Hash.h from espressif framework if the first include was from the crypto library
@ -50,8 +52,6 @@
#define DEFAULT_MAX_WS_CLIENTS 4 #define DEFAULT_MAX_WS_CLIENTS 4
#endif #endif
using AsyncWebSocketMessageBuffer = std::shared_ptr<std::vector<uint8_t>>;
class AsyncWebSocket; class AsyncWebSocket;
class AsyncWebSocketResponse; class AsyncWebSocketResponse;
class AsyncWebSocketClient; class AsyncWebSocketClient;
@ -86,26 +86,78 @@ typedef enum { WS_CONTINUATION, WS_TEXT, WS_BINARY, WS_DISCONNECT = 0x08, WS_PIN
typedef enum { WS_MSG_SENDING, WS_MSG_SENT, WS_MSG_ERROR } AwsMessageStatus; typedef enum { WS_MSG_SENDING, WS_MSG_SENT, WS_MSG_ERROR } AwsMessageStatus;
typedef enum { WS_EVT_CONNECT, WS_EVT_DISCONNECT, WS_EVT_PONG, WS_EVT_ERROR, WS_EVT_DATA } AwsEventType; typedef enum { WS_EVT_CONNECT, WS_EVT_DISCONNECT, WS_EVT_PONG, WS_EVT_ERROR, WS_EVT_DATA } AwsEventType;
class AsyncWebSocketMessageBuffer {
private:
uint8_t * _data;
size_t _len;
bool _lock;
uint32_t _count;
class AsyncWebSocketMessage public:
{ AsyncWebSocketMessageBuffer();
private: AsyncWebSocketMessageBuffer(size_t size);
std::shared_ptr<std::vector<uint8_t>> _WSbuffer; AsyncWebSocketMessageBuffer(uint8_t * data, size_t size);
uint8_t _opcode{WS_TEXT}; AsyncWebSocketMessageBuffer(const AsyncWebSocketMessageBuffer &);
bool _mask{false}; AsyncWebSocketMessageBuffer(AsyncWebSocketMessageBuffer &&);
AwsMessageStatus _status{WS_MSG_ERROR}; ~AsyncWebSocketMessageBuffer();
size_t _sent{}; void operator ++(int i) { (void)i; _count++; }
size_t _ack{}; void operator --(int i) { (void)i; if (_count > 0) { _count--; } ; }
size_t _acked{}; bool reserve(size_t size);
void lock() { _lock = true; }
void unlock() { _lock = false; }
uint8_t * get() { return _data; }
size_t length() { return _len; }
uint32_t count() { return _count; }
bool canDelete() { return (!_count && !_lock); }
friend AsyncWebSocket;
};
class AsyncWebSocketMessage {
protected:
uint8_t _opcode;
bool _mask;
AwsMessageStatus _status;
public:
AsyncWebSocketMessage():_opcode(WS_TEXT),_mask(false),_status(WS_MSG_ERROR){}
virtual ~AsyncWebSocketMessage(){}
virtual void ack(size_t len __attribute__((unused)), uint32_t time __attribute__((unused))){}
virtual size_t send(AsyncClient *client __attribute__((unused))){ return 0; }
virtual bool finished(){ return _status != WS_MSG_SENDING; }
virtual bool betweenFrames() const { return false; }
};
class AsyncWebSocketBasicMessage: public AsyncWebSocketMessage {
private:
size_t _len;
size_t _sent;
size_t _ack;
size_t _acked;
uint8_t * _data;
public: public:
AsyncWebSocketMessage(std::shared_ptr<std::vector<uint8_t>> buffer, uint8_t opcode=WS_TEXT, bool mask=false); AsyncWebSocketBasicMessage(const char * data, size_t len, uint8_t opcode=WS_TEXT, bool mask=false);
AsyncWebSocketBasicMessage(uint8_t opcode=WS_TEXT, bool mask=false);
virtual ~AsyncWebSocketBasicMessage() override;
virtual bool betweenFrames() const override { return _acked == _ack; }
virtual void ack(size_t len, uint32_t time) override ;
virtual size_t send(AsyncClient *client) override ;
};
bool finished() const { return _status != WS_MSG_SENDING; } class AsyncWebSocketMultiMessage: public AsyncWebSocketMessage {
bool betweenFrames() const { return _acked == _ack; } private:
uint8_t * _data;
void ack(size_t len, uint32_t time); size_t _len;
size_t send(AsyncClient *client); size_t _sent;
size_t _ack;
size_t _acked;
AsyncWebSocketMessageBuffer * _WSbuffer;
public:
AsyncWebSocketMultiMessage(AsyncWebSocketMessageBuffer * buffer, uint8_t opcode=WS_TEXT, bool mask=false);
virtual ~AsyncWebSocketMultiMessage() override;
virtual bool betweenFrames() const override { return _acked == _ack; }
virtual void ack(size_t len, uint32_t time) override ;
virtual size_t send(AsyncClient *client) override ;
}; };
class AsyncWebSocketClient { class AsyncWebSocketClient {
@ -115,10 +167,8 @@ class AsyncWebSocketClient {
uint32_t _clientId; uint32_t _clientId;
AwsClientStatus _status; AwsClientStatus _status;
AsyncWebLock _lock; LinkedList<AsyncWebSocketControl *> _controlQueue;
LinkedList<AsyncWebSocketMessage *> _messageQueue;
std::deque<AsyncWebSocketControl> _controlQueue;
std::deque<AsyncWebSocketMessage> _messageQueue;
uint8_t _pstate; uint8_t _pstate;
AwsFrameInfo _pinfo; AwsFrameInfo _pinfo;
@ -126,8 +176,8 @@ class AsyncWebSocketClient {
uint32_t _lastMessageTime; uint32_t _lastMessageTime;
uint32_t _keepAlivePeriod; uint32_t _keepAlivePeriod;
void _queueControl(uint8_t opcode, const uint8_t *data=NULL, size_t len=0, bool mask=false); void _queueMessage(AsyncWebSocketMessage *dataMessage);
void _queueMessage(std::shared_ptr<std::vector<uint8_t>> buffer, uint8_t opcode=WS_TEXT, bool mask=false); void _queueControl(AsyncWebSocketControl *controlMessage);
void _runQueue(); void _runQueue();
void _clearQueue(); void _clearQueue();
@ -138,22 +188,18 @@ class AsyncWebSocketClient {
~AsyncWebSocketClient(); ~AsyncWebSocketClient();
//client id increments for the given server //client id increments for the given server
uint32_t id() const { return _clientId; } uint32_t id(){ return _clientId; }
AwsClientStatus status() const { return _status; } AwsClientStatus status(){ return _status; }
AsyncClient* client() { return _client; } AsyncClient* client(){ return _client; }
const AsyncClient* client() const { return _client; }
AsyncWebSocket *server(){ return _server; } AsyncWebSocket *server(){ return _server; }
const AsyncWebSocket *server() const { return _server; }
AwsFrameInfo const &pinfo() const { return _pinfo; } AwsFrameInfo const &pinfo() const { return _pinfo; }
IPAddress remoteIP() const; IPAddress remoteIP();
uint16_t remotePort() const; uint16_t remotePort();
bool shouldBeDeleted() const { return !_client; }
//control frames //control frames
void close(uint16_t code=0, const char * message=NULL); void close(uint16_t code=0, const char * message=NULL);
void ping(const uint8_t *data=NULL, size_t len=0); void ping(uint8_t *data=NULL, size_t len=0);
//set auto-ping period in seconds. disabled if zero (default) //set auto-ping period in seconds. disabled if zero (default)
void keepAlivePeriod(uint16_t seconds){ void keepAlivePeriod(uint16_t seconds){
@ -164,49 +210,31 @@ class AsyncWebSocketClient {
} }
//data packets //data packets
/** void message(AsyncWebSocketMessage *message){ _queueMessage(message); }
* @brief allocate memory buffer owned by shared-pointer and copy provided data bool queueIsFull();
* used to keep the data untill websocket send is complete for single/multiple clients size_t queueLen() { return _messageQueue.length() + _controlQueue.length(); }
*
* @param message
* @param len
* @return AsyncWebSocketMessageBuffer
*/
AsyncWebSocketMessageBuffer makeBuffer(const uint8_t *message, size_t len);
/**
* @brief allocate empty memory buffer owned by shared-pointer
* used to keep the data untill websocket send is complete for single/multiple clients
*
* @param len
* @return AsyncWebSocketMessageBuffer
*/
inline AsyncWebSocketMessageBuffer makeBuffer(size_t len){ return std::make_shared<std::vector<uint8_t>>(len); };
void message(AsyncWebSocketMessageBuffer buffer, uint8_t opcode=WS_TEXT, bool mask=false) { _queueMessage(buffer, opcode, mask); }
bool queueIsFull() const;
size_t queueLen() const;
size_t printf(const char *format, ...) __attribute__ ((format (printf, 2, 3))); size_t printf(const char *format, ...) __attribute__ ((format (printf, 2, 3)));
#ifndef ESP32 #ifndef ESP32
size_t printf_P(PGM_P formatP, ...) __attribute__ ((format (printf, 2, 3))); size_t printf_P(PGM_P formatP, ...) __attribute__ ((format (printf, 2, 3)));
#endif #endif
void text(const char * message, size_t len);
void text(const char * message);
void text(uint8_t * message, size_t len);
void text(char * message);
void text(const String &message);
void text(const __FlashStringHelper *data);
void text(AsyncWebSocketMessageBuffer *buffer);
inline void text(AsyncWebSocketMessageBuffer buffer){ _queueMessage(buffer); }; void binary(const char * message, size_t len);
inline void text(const uint8_t *message, size_t len){ text(makeBuffer(message, len)); }; void binary(const char * message);
inline void text(const char *message, size_t len){ text((const uint8_t *)message, len); }; void binary(uint8_t * message, size_t len);
inline void text(const char *message){ text(message, strlen(message)); }; void binary(char * message);
inline void text(const String &message){ text(message.c_str(), message.length()); }; void binary(const String &message);
void text(const __FlashStringHelper *message); void binary(const __FlashStringHelper *data, size_t len);
void binary(AsyncWebSocketMessageBuffer *buffer);
inline void binary(AsyncWebSocketMessageBuffer buffer){ _queueMessage(buffer, WS_BINARY); }; bool canSend() { return _messageQueue.length() < WS_MAX_QUEUED_MESSAGES; }
inline void binary(const uint8_t *message, size_t len){ binary(makeBuffer(message, len)); };
inline void binary(const char * message, size_t len){ binary((const uint8_t *)message, len); };
inline void binary(const char * message){ binary(message, strlen(message)); };
inline void binary(const String &message){ binary(message.c_str(), message.length()); };
void binary(const __FlashStringHelper *message, size_t len);
bool canSend() const;
//system callbacks (do not call) //system callbacks (do not call)
void _onAck(size_t len, uint32_t time); void _onAck(size_t len, uint32_t time);
@ -222,9 +250,11 @@ typedef std::function<void(AsyncWebSocket * server, AsyncWebSocketClient * clien
//WebServer Handler implementation that plays the role of a socket server //WebServer Handler implementation that plays the role of a socket server
class AsyncWebSocket: public AsyncWebHandler { class AsyncWebSocket: public AsyncWebHandler {
public:
typedef LinkedList<AsyncWebSocketClient *> AsyncWebSocketClientLinkedList;
private: private:
String _url; String _url;
std::list<AsyncWebSocketClient> _clients; AsyncWebSocketClientLinkedList _clients;
uint32_t _cNextId; uint32_t _cNextId;
AwsEventHandler _eventHandler; AwsEventHandler _eventHandler;
AwsHandshakeHandler _handshakeHandler; AwsHandshakeHandler _handshakeHandler;
@ -248,56 +278,41 @@ class AsyncWebSocket: public AsyncWebHandler {
void closeAll(uint16_t code=0, const char * message=NULL); void closeAll(uint16_t code=0, const char * message=NULL);
void cleanupClients(uint16_t maxClients = DEFAULT_MAX_WS_CLIENTS); void cleanupClients(uint16_t maxClients = DEFAULT_MAX_WS_CLIENTS);
void ping(uint32_t id, const uint8_t *data=NULL, size_t len=0); void ping(uint32_t id, uint8_t *data=NULL, size_t len=0);
void pingAll(const uint8_t *data=NULL, size_t len=0); // done void pingAll(uint8_t *data=NULL, size_t len=0); // done
//data packets void text(uint32_t id, const char * message, size_t len);
/** void text(uint32_t id, const char * message);
* @brief allocate memory buffer owned by shared-pointer and copy provided data void text(uint32_t id, uint8_t * message, size_t len);
* used to keep the data untill websocket send is complete for single/multiple clients void text(uint32_t id, char * message);
* void text(uint32_t id, const String &message);
* @param message
* @param len
* @return AsyncWebSocketMessageBuffer
*/
AsyncWebSocketMessageBuffer makeBuffer(const uint8_t *message, size_t len);
/**
* @brief allocate empty memory buffer owned by shared-pointer
* used to keep the data untill websocket send is complete for single/multiple clients
*
* @param len
* @return AsyncWebSocketMessageBuffer
*/
inline AsyncWebSocketMessageBuffer makeBuffer(size_t len){ return std::make_shared<std::vector<uint8_t>>(len); };
void text(uint32_t id, AsyncWebSocketMessageBuffer message);
void text(uint32_t id, const uint8_t * message, size_t len);
inline void text(uint32_t id, const char *message, size_t len){ text(id, (const uint8_t *)message, len); };
inline void text(uint32_t id, const char *message){ text(id, message, strlen(message)); };
inline void text(uint32_t id, const String &message){ text(id, message.c_str(), message.length()); };
void text(uint32_t id, const __FlashStringHelper *message); void text(uint32_t id, const __FlashStringHelper *message);
void textAll(AsyncWebSocketMessageBuffer buffer);
void textAll(const uint8_t *message, size_t len);
void textAll(const char * message, size_t len); void textAll(const char * message, size_t len);
void textAll(const char * message); void textAll(const char * message);
void textAll(uint8_t * message, size_t len);
void textAll(char * message);
void textAll(const String &message); void textAll(const String &message);
void textAll(const __FlashStringHelper *message); // need to convert void textAll(const __FlashStringHelper *message); // need to convert
void textAll(AsyncWebSocketMessageBuffer * buffer);
void binary(uint32_t id, AsyncWebSocketMessageBuffer message); void binary(uint32_t id, const char * message, size_t len);
void binary(uint32_t id, const uint8_t *message, size_t len); void binary(uint32_t id, const char * message);
void binary(uint32_t id, const char *message, size_t len); void binary(uint32_t id, uint8_t * message, size_t len);
void binary(uint32_t id, const char *message); void binary(uint32_t id, char * message);
void binary(uint32_t id, const String &message); void binary(uint32_t id, const String &message);
void binary(uint32_t id, const __FlashStringHelper *message, size_t len); void binary(uint32_t id, const __FlashStringHelper *message, size_t len);
void binaryAll(AsyncWebSocketMessageBuffer buffer); void binaryAll(const char * message, size_t len);
void binaryAll(const uint8_t *message, size_t len); void binaryAll(const char * message);
void binaryAll(const char *message, size_t len); void binaryAll(uint8_t * message, size_t len);
void binaryAll(const char *message); void binaryAll(char * message);
void binaryAll(const String &message); void binaryAll(const String &message);
void binaryAll(const __FlashStringHelper *message, size_t len); void binaryAll(const __FlashStringHelper *message, size_t len);
void binaryAll(AsyncWebSocketMessageBuffer * buffer);
void message(uint32_t id, AsyncWebSocketMessage *message);
void messageAll(AsyncWebSocketMultiMessage *message);
size_t printf(uint32_t id, const char *format, ...) __attribute__ ((format (printf, 3, 4))); size_t printf(uint32_t id, const char *format, ...) __attribute__ ((format (printf, 3, 4)));
size_t printfAll(const char *format, ...) __attribute__ ((format (printf, 2, 3))); size_t printfAll(const char *format, ...) __attribute__ ((format (printf, 2, 3)));
@ -318,12 +333,20 @@ class AsyncWebSocket: public AsyncWebHandler {
//system callbacks (do not call) //system callbacks (do not call)
uint32_t _getNextId(){ return _cNextId++; } uint32_t _getNextId(){ return _cNextId++; }
AsyncWebSocketClient *_newClient(AsyncWebServerRequest *request); void _addClient(AsyncWebSocketClient * client);
void _handleDisconnect(AsyncWebSocketClient * client);
void _handleEvent(AsyncWebSocketClient * client, AwsEventType type, void * arg, uint8_t *data, size_t len); void _handleEvent(AsyncWebSocketClient * client, AwsEventType type, void * arg, uint8_t *data, size_t len);
virtual bool canHandle(AsyncWebServerRequest *request) override final; virtual bool canHandle(AsyncWebServerRequest *request) override final;
virtual void handleRequest(AsyncWebServerRequest *request) override final; virtual void handleRequest(AsyncWebServerRequest *request) override final;
const std::list<AsyncWebSocketClient> &getClients() const { return _clients; }
// messagebuffer functions/objects.
AsyncWebSocketMessageBuffer * makeBuffer(size_t size = 0);
AsyncWebSocketMessageBuffer * makeBuffer(uint8_t * data, size_t size);
LinkedList<AsyncWebSocketMessageBuffer *> _buffers;
void _cleanBuffers();
AsyncWebSocketClientLinkedList getClients() const;
}; };
//WebServer response to authenticate the socket and detach the tcp client from the web server request //WebServer response to authenticate the socket and detach the tcp client from the web server request

View File

@ -7,52 +7,16 @@
#ifdef ESP32 #ifdef ESP32
// This is the ESP32 version of the Sync Lock, using the FreeRTOS Semaphore
// Modified 'AsyncWebLock' to just only use mutex since pxCurrentTCB is not
// always available. According to example by Arjan Filius, changed name,
// added unimplemented version for ESP8266
class AsyncPlainLock
{
private:
SemaphoreHandle_t _lock;
public:
AsyncPlainLock() {
_lock = xSemaphoreCreateBinary();
// In this fails, the system is likely that much out of memory that
// we should abort anyways. If assertions are disabled, nothing is lost..
assert(_lock);
xSemaphoreGive(_lock);
}
~AsyncPlainLock() {
vSemaphoreDelete(_lock);
}
bool lock() const {
xSemaphoreTake(_lock, portMAX_DELAY);
return true;
}
void unlock() const {
xSemaphoreGive(_lock);
}
};
// This is the ESP32 version of the Sync Lock, using the FreeRTOS Semaphore // This is the ESP32 version of the Sync Lock, using the FreeRTOS Semaphore
class AsyncWebLock class AsyncWebLock
{ {
private: private:
SemaphoreHandle_t _lock; SemaphoreHandle_t _lock;
mutable TaskHandle_t _lockedBy{}; mutable void *_lockedBy;
public: public:
AsyncWebLock() AsyncWebLock() {
{
_lock = xSemaphoreCreateBinary(); _lock = xSemaphoreCreateBinary();
// In this fails, the system is likely that much out of memory that
// we should abort anyways. If assertions are disabled, nothing is lost..
assert(_lock);
_lockedBy = NULL; _lockedBy = NULL;
xSemaphoreGive(_lock); xSemaphoreGive(_lock);
} }
@ -62,10 +26,10 @@ public:
} }
bool lock() const { bool lock() const {
const auto currentTask = xTaskGetCurrentTaskHandle(); extern void *pxCurrentTCB;
if (_lockedBy != currentTask) { if (_lockedBy != pxCurrentTCB) {
xSemaphoreTake(_lock, portMAX_DELAY); xSemaphoreTake(_lock, portMAX_DELAY);
_lockedBy = currentTask; _lockedBy = pxCurrentTCB;
return true; return true;
} }
return false; return false;
@ -97,10 +61,6 @@ public:
void unlock() const { void unlock() const {
} }
}; };
// Same for AsyncPlainLock, for ESP8266 this is just the unimplemented version above.
using AsyncPlainLock = AsyncWebLock;
#endif #endif
class AsyncWebLockGuard class AsyncWebLockGuard
@ -122,13 +82,6 @@ public:
_lock->unlock(); _lock->unlock();
} }
} }
void unlock() {
if (_lock) {
_lock->unlock();
_lock = NULL;
}
}
}; };
#endif // ASYNCWEBSYNCHRONIZATION_H_ #endif // ASYNCWEBSYNCHRONIZATION_H_

View File

@ -24,8 +24,6 @@
#include "Arduino.h" #include "Arduino.h"
#include <functional> #include <functional>
#include <list>
#include <vector>
#include "FS.h" #include "FS.h"
#include "StringArray.h" #include "StringArray.h"
@ -123,9 +121,6 @@ class AsyncWebHeader {
String _value; String _value;
public: public:
AsyncWebHeader() = default;
AsyncWebHeader(const AsyncWebHeader &) = default;
AsyncWebHeader(const String& name, const String& value): _name(name), _value(value){} AsyncWebHeader(const String& name, const String& value): _name(name), _value(value){}
AsyncWebHeader(const String& data): _name(), _value(){ AsyncWebHeader(const String& data): _name(), _value(){
if(!data) return; if(!data) return;
@ -134,12 +129,10 @@ class AsyncWebHeader {
_name = data.substring(0, index); _name = data.substring(0, index);
_value = data.substring(index + 2); _value = data.substring(index + 2);
} }
~AsyncWebHeader(){}
AsyncWebHeader &operator=(const AsyncWebHeader &) = default;
const String& name() const { return _name; } const String& name() const { return _name; }
const String& value() const { return _value; } const String& value() const { return _value; }
String toString() const { return _name + F(": ") + _value + F("\r\n"); } String toString() const { return String(_name + F(": ") + _value + F("\r\n")); }
}; };
/* /*
@ -161,7 +154,7 @@ class AsyncWebServerRequest {
AsyncWebServer* _server; AsyncWebServer* _server;
AsyncWebHandler* _handler; AsyncWebHandler* _handler;
AsyncWebServerResponse* _response; AsyncWebServerResponse* _response;
std::vector<String> _interestingHeaders; StringArray _interestingHeaders;
ArDisconnectHandler _onDisconnectfn; ArDisconnectHandler _onDisconnectfn;
String _temp; String _temp;
@ -183,9 +176,9 @@ class AsyncWebServerRequest {
size_t _contentLength; size_t _contentLength;
size_t _parsedLength; size_t _parsedLength;
std::list<AsyncWebHeader> _headers; LinkedList<AsyncWebHeader *> _headers;
LinkedList<AsyncWebParameter *> _params; LinkedList<AsyncWebParameter *> _params;
std::vector<String> _pathParams; LinkedList<String *> _pathParams;
uint8_t _multiParseState; uint8_t _multiParseState;
uint8_t _boundaryPosition; uint8_t _boundaryPosition;
@ -277,12 +270,9 @@ class AsyncWebServerRequest {
bool hasHeader(const String& name) const; // check if header exists bool hasHeader(const String& name) const; // check if header exists
bool hasHeader(const __FlashStringHelper * data) const; // check if header exists bool hasHeader(const __FlashStringHelper * data) const; // check if header exists
AsyncWebHeader* getHeader(const String& name); AsyncWebHeader* getHeader(const String& name) const;
const AsyncWebHeader* getHeader(const String& name) const; AsyncWebHeader* getHeader(const __FlashStringHelper * data) const;
AsyncWebHeader* getHeader(const __FlashStringHelper * data); AsyncWebHeader* getHeader(size_t num) const;
const AsyncWebHeader* getHeader(const __FlashStringHelper * data) const;
AsyncWebHeader* getHeader(size_t num);
const AsyncWebHeader* getHeader(size_t num) const;
size_t params() const; // get arguments count size_t params() const; // get arguments count
bool hasParam(const String& name, bool post=false, bool file=false) const; bool hasParam(const String& name, bool post=false, bool file=false) const;
@ -381,7 +371,7 @@ typedef enum {
class AsyncWebServerResponse { class AsyncWebServerResponse {
protected: protected:
int _code; int _code;
std::list<AsyncWebHeader> _headers; LinkedList<AsyncWebHeader *> _headers;
String _contentType; String _contentType;
size_t _contentLength; size_t _contentLength;
bool _sendContentLength; bool _sendContentLength;
@ -464,16 +454,17 @@ class AsyncWebServer {
}; };
class DefaultHeaders { class DefaultHeaders {
using headers_t = std::list<AsyncWebHeader>; using headers_t = LinkedList<AsyncWebHeader *>;
headers_t _headers; headers_t _headers;
DefaultHeaders()
:_headers(headers_t([](AsyncWebHeader *h){ delete h; }))
{}
public: public:
DefaultHeaders() = default; using ConstIterator = headers_t::ConstIterator;
using ConstIterator = headers_t::const_iterator;
void addHeader(const String& name, const String& value){ void addHeader(const String& name, const String& value){
_headers.emplace_back(name, value); _headers.add(new AsyncWebHeader(name, value));
} }
ConstIterator begin() const { return _headers.begin(); } ConstIterator begin() const { return _headers.begin(); }
@ -481,7 +472,6 @@ public:
DefaultHeaders(DefaultHeaders const &) = delete; DefaultHeaders(DefaultHeaders const &) = delete;
DefaultHeaders &operator=(DefaultHeaders const &) = delete; DefaultHeaders &operator=(DefaultHeaders const &) = delete;
static DefaultHeaders &Instance() { static DefaultHeaders &Instance() {
static DefaultHeaders instance; static DefaultHeaders instance;
return instance; return instance;

View File

@ -47,10 +47,19 @@ class LinkedList {
class Iterator { class Iterator {
ItemType* _node; ItemType* _node;
ItemType* _nextNode = nullptr;
public: public:
Iterator(ItemType* current = nullptr) : _node(current) {} Iterator(ItemType* current = nullptr) : _node(current) {
if (_node != nullptr) {
_nextNode = current->next;
}
}
Iterator(const Iterator& i) : _node(i._node) {} Iterator(const Iterator& i) : _node(i._node) {}
Iterator& operator ++() { _node = _node->next; return *this; } Iterator& operator ++() {
_node = _nextNode;
_nextNode = _node != nullptr ? _node->next : nullptr;
return *this;
}
bool operator != (const Iterator& i) const { return _node != i._node; } bool operator != (const Iterator& i) const { return _node != i._node; }
const T& operator * () const { return _node->value(); } const T& operator * () const { return _node->value(); }
const T* operator -> () const { return &_node->value(); } const T* operator -> () const { return &_node->value(); }
@ -171,4 +180,23 @@ class LinkedList {
} }
}; };
class StringArray : public LinkedList<String> {
public:
StringArray() : LinkedList(nullptr) {}
bool containsIgnoreCase(const String& str){
for (const auto& s : *this) {
if (str.equalsIgnoreCase(s)) {
return true;
}
}
return false;
}
};
#endif /* STRINGARRAY_H_ */ #endif /* STRINGARRAY_H_ */

View File

@ -77,9 +77,9 @@ static bool getMD5(uint8_t * data, uint16_t len, char * output){//33 bytes or mo
memset(_buf, 0x00, 16); memset(_buf, 0x00, 16);
#ifdef ESP32 #ifdef ESP32
mbedtls_md5_init(&_ctx); mbedtls_md5_init(&_ctx);
mbedtls_md5_starts_ret(&_ctx); mbedtls_md5_starts(&_ctx);
mbedtls_md5_update_ret(&_ctx, data, len); mbedtls_md5_update(&_ctx, data, len);
mbedtls_md5_finish_ret(&_ctx, _buf); mbedtls_md5_finish(&_ctx, _buf);
#else #else
MD5Init(&_ctx); MD5Init(&_ctx);
MD5Update(&_ctx, data, len); MD5Update(&_ctx, data, len);

View File

@ -51,7 +51,9 @@ AsyncWebServerRequest::AsyncWebServerRequest(AsyncWebServer* s, AsyncClient* c)
, _expectingContinue(false) , _expectingContinue(false)
, _contentLength(0) , _contentLength(0)
, _parsedLength(0) , _parsedLength(0)
, _headers(LinkedList<AsyncWebHeader *>([](AsyncWebHeader *h){ delete h; }))
, _params(LinkedList<AsyncWebParameter *>([](AsyncWebParameter *p){ delete p; })) , _params(LinkedList<AsyncWebParameter *>([](AsyncWebParameter *p){ delete p; }))
, _pathParams(LinkedList<String *>([](String *p){ delete p; }))
, _multiParseState(0) , _multiParseState(0)
, _boundaryPosition(0) , _boundaryPosition(0)
, _itemStartIndex(0) , _itemStartIndex(0)
@ -74,12 +76,12 @@ AsyncWebServerRequest::AsyncWebServerRequest(AsyncWebServer* s, AsyncClient* c)
} }
AsyncWebServerRequest::~AsyncWebServerRequest(){ AsyncWebServerRequest::~AsyncWebServerRequest(){
_headers.clear(); _headers.free();
_params.free(); _params.free();
_pathParams.clear(); _pathParams.free();
_interestingHeaders.clear(); _interestingHeaders.free();
if(_response != NULL){ if(_response != NULL){
delete _response; delete _response;
@ -180,19 +182,11 @@ void AsyncWebServerRequest::_onData(void *buf, size_t len){
} }
void AsyncWebServerRequest::_removeNotInterestingHeaders(){ void AsyncWebServerRequest::_removeNotInterestingHeaders(){
if (std::any_of(std::begin(_interestingHeaders), std::end(_interestingHeaders), if (_interestingHeaders.containsIgnoreCase(F("ANY"))) return; // nothing to do
[](const String &str){ return str.equalsIgnoreCase(F("ANY")); })) for(const auto& header: _headers){
return; // nothing to do if(!_interestingHeaders.containsIgnoreCase(header->name().c_str())){
_headers.remove(header);
for(auto iter = std::begin(_headers); iter != std::end(_headers); ) }
{
const auto name = iter->name();
if (std::none_of(std::begin(_interestingHeaders), std::end(_interestingHeaders),
[&name](const String &str){ return str.equalsIgnoreCase(name); }))
iter = _headers.erase(iter);
else
iter++;
} }
} }
@ -253,7 +247,7 @@ void AsyncWebServerRequest::_addParam(AsyncWebParameter *p){
} }
void AsyncWebServerRequest::_addPathParam(const char *p){ void AsyncWebServerRequest::_addPathParam(const char *p){
_pathParams.emplace_back(p); _pathParams.add(new String(p));
} }
void AsyncWebServerRequest::_addGetParams(const String& params){ void AsyncWebServerRequest::_addGetParams(const String& params){
@ -335,7 +329,8 @@ bool AsyncWebServerRequest::_parseReqHeader(){
int index = _temp.indexOf(':'); int index = _temp.indexOf(':');
if(index){ if(index){
String name = _temp.substring(0, index); String name = _temp.substring(0, index);
String value = _temp.substring(index + 2); String value = _temp.substring(index + 1);
value.trim();
if(name.equalsIgnoreCase("Host")){ if(name.equalsIgnoreCase("Host")){
_host = value; _host = value;
} else if(name.equalsIgnoreCase(F("Content-Type"))){ } else if(name.equalsIgnoreCase(F("Content-Type"))){
@ -367,7 +362,7 @@ bool AsyncWebServerRequest::_parseReqHeader(){
} }
} }
} }
_headers.emplace_back(name, value); _headers.add(new AsyncWebHeader(name, value));
} }
_temp = String(); _temp = String();
return true; return true;
@ -608,12 +603,12 @@ void AsyncWebServerRequest::_parseLine(){
} }
size_t AsyncWebServerRequest::headers() const{ size_t AsyncWebServerRequest::headers() const{
return _headers.size(); return _headers.length();
} }
bool AsyncWebServerRequest::hasHeader(const String& name) const { bool AsyncWebServerRequest::hasHeader(const String& name) const {
for(const auto& h: _headers){ for(const auto& h: _headers){
if(h.name().equalsIgnoreCase(name)){ if(h->name().equalsIgnoreCase(name)){
return true; return true;
} }
} }
@ -624,64 +619,22 @@ bool AsyncWebServerRequest::hasHeader(const __FlashStringHelper * data) const {
return hasHeader(String(data)); return hasHeader(String(data));
} }
AsyncWebHeader* AsyncWebServerRequest::getHeader(const String& name) { AsyncWebHeader* AsyncWebServerRequest::getHeader(const String& name) const {
auto iter = std::find_if(std::begin(_headers), std::end(_headers), for(const auto& h: _headers){
[&name](const AsyncWebHeader &header){ return header.name().equalsIgnoreCase(name); }); if(h->name().equalsIgnoreCase(name)){
return h;
if (iter == std::end(_headers))
return nullptr;
return &(*iter);
}
const AsyncWebHeader* AsyncWebServerRequest::getHeader(const String& name) const {
auto iter = std::find_if(std::begin(_headers), std::end(_headers),
[&name](const AsyncWebHeader &header){ return header.name().equalsIgnoreCase(name); });
if (iter == std::end(_headers))
return nullptr;
return &(*iter);
}
AsyncWebHeader* AsyncWebServerRequest::getHeader(const __FlashStringHelper * data) {
PGM_P p = reinterpret_cast<PGM_P>(data);
size_t n = strlen_P(p);
char * name = (char*) malloc(n+1);
if (name) {
strcpy_P(name, p);
AsyncWebHeader* result = getHeader( String(name));
free(name);
return result;
} else {
return nullptr;
} }
}
const AsyncWebHeader* AsyncWebServerRequest::getHeader(const __FlashStringHelper * data) const {
PGM_P p = reinterpret_cast<PGM_P>(data);
size_t n = strlen_P(p);
char * name = (char*) malloc(n+1);
if (name) {
strcpy_P(name, p);
const AsyncWebHeader* result = getHeader( String(name));
free(name);
return result;
} else {
return nullptr;
} }
return nullptr;
} }
AsyncWebHeader* AsyncWebServerRequest::getHeader(size_t num) { AsyncWebHeader* AsyncWebServerRequest::getHeader(const __FlashStringHelper * data) const {
if (num >= _headers.size()) return getHeader(String(data));
return nullptr;
return &(*std::next(std::begin(_headers), num));
} }
const AsyncWebHeader* AsyncWebServerRequest::getHeader(size_t num) const { AsyncWebHeader* AsyncWebServerRequest::getHeader(size_t num) const {
if (num >= _headers.size()) auto header = _headers.nth(num);
return nullptr; return header ? *header : nullptr;
return &(*std::next(std::begin(_headers), num));
} }
size_t AsyncWebServerRequest::params() const { size_t AsyncWebServerRequest::params() const {
@ -720,9 +673,8 @@ AsyncWebParameter* AsyncWebServerRequest::getParam(size_t num) const {
} }
void AsyncWebServerRequest::addInterestingHeader(const String& name){ void AsyncWebServerRequest::addInterestingHeader(const String& name){
if(std::none_of(std::begin(_interestingHeaders), std::end(_interestingHeaders), if(!_interestingHeaders.containsIgnoreCase(name))
[&name](const String &str){ return str.equalsIgnoreCase(name); })) _interestingHeaders.add(name);
_interestingHeaders.push_back(name);
} }
void AsyncWebServerRequest::send(AsyncWebServerResponse *response){ void AsyncWebServerRequest::send(AsyncWebServerResponse *response){
@ -914,11 +866,12 @@ const String& AsyncWebServerRequest::argName(size_t i) const {
} }
const String& AsyncWebServerRequest::pathArg(size_t i) const { const String& AsyncWebServerRequest::pathArg(size_t i) const {
return i < _pathParams.size() ? _pathParams[i] : emptyString; auto param = _pathParams.nth(i);
return param ? **param : emptyString;
} }
const String& AsyncWebServerRequest::header(const char* name) const { const String& AsyncWebServerRequest::header(const char* name) const {
const AsyncWebHeader* h = getHeader(String(name)); AsyncWebHeader* h = getHeader(String(name));
return h ? h->value() : emptyString; return h ? h->value() : emptyString;
} }
@ -928,12 +881,12 @@ const String& AsyncWebServerRequest::header(const __FlashStringHelper * data) co
const String& AsyncWebServerRequest::header(size_t i) const { const String& AsyncWebServerRequest::header(size_t i) const {
const AsyncWebHeader* h = getHeader(i); AsyncWebHeader* h = getHeader(i);
return h ? h->value() : emptyString; return h ? h->value() : emptyString;
} }
const String& AsyncWebServerRequest::headerName(size_t i) const { const String& AsyncWebServerRequest::headerName(size_t i) const {
const AsyncWebHeader* h = getHeader(i); AsyncWebHeader* h = getHeader(i);
return h ? h->name() : emptyString; return h ? h->name() : emptyString;
} }

View File

@ -27,8 +27,6 @@
#undef max #undef max
#endif #endif
#include <vector> #include <vector>
#include <memory>
// It is possible to restore these defines, but one can use _min and _max instead. Or std::min, std::max. // It is possible to restore these defines, but one can use _min and _max instead. Or std::min, std::max.
class AsyncBasicResponse: public AsyncWebServerResponse { class AsyncBasicResponse: public AsyncWebServerResponse {
@ -124,7 +122,7 @@ class cbuf;
class AsyncResponseStream: public AsyncAbstractResponse, public Print { class AsyncResponseStream: public AsyncAbstractResponse, public Print {
private: private:
std::unique_ptr<cbuf> _content; cbuf *_content;
public: public:
AsyncResponseStream(const String& contentType, size_t bufferSize); AsyncResponseStream(const String& contentType, size_t bufferSize);
~AsyncResponseStream(); ~AsyncResponseStream();

View File

@ -88,6 +88,7 @@ const __FlashStringHelper *AsyncWebServerResponse::responseCodeToString(int code
AsyncWebServerResponse::AsyncWebServerResponse() AsyncWebServerResponse::AsyncWebServerResponse()
: _code(0) : _code(0)
, _headers(LinkedList<AsyncWebHeader *>([](AsyncWebHeader *h){ delete h; }))
, _contentType() , _contentType()
, _contentLength(0) , _contentLength(0)
, _sendContentLength(true) , _sendContentLength(true)
@ -98,12 +99,14 @@ AsyncWebServerResponse::AsyncWebServerResponse()
, _writtenLength(0) , _writtenLength(0)
, _state(RESPONSE_SETUP) , _state(RESPONSE_SETUP)
{ {
for(const auto &header: DefaultHeaders::Instance()) { for(auto header: DefaultHeaders::Instance()) {
_headers.emplace_back(header); _headers.add(new AsyncWebHeader(header->name(), header->value()));
} }
} }
AsyncWebServerResponse::~AsyncWebServerResponse() = default; AsyncWebServerResponse::~AsyncWebServerResponse(){
_headers.free();
}
void AsyncWebServerResponse::setCode(int code){ void AsyncWebServerResponse::setCode(int code){
if(_state == RESPONSE_SETUP) if(_state == RESPONSE_SETUP)
@ -121,7 +124,7 @@ void AsyncWebServerResponse::setContentType(const String& type){
} }
void AsyncWebServerResponse::addHeader(const String& name, const String& value){ void AsyncWebServerResponse::addHeader(const String& name, const String& value){
_headers.emplace_back(name, value); _headers.add(new AsyncWebHeader(name, value));
} }
String AsyncWebServerResponse::_assembleHead(uint8_t version){ String AsyncWebServerResponse::_assembleHead(uint8_t version){
@ -147,10 +150,10 @@ String AsyncWebServerResponse::_assembleHead(uint8_t version){
} }
for(const auto& header: _headers){ for(const auto& header: _headers){
snprintf_P(buf, bufSize, PSTR("%s: %s\r\n"), header.name().c_str(), header.value().c_str()); snprintf_P(buf, bufSize, PSTR("%s: %s\r\n"), header->name().c_str(), header->value().c_str());
out.concat(buf); out.concat(buf);
} }
_headers.clear(); _headers.free();
out.concat(F("\r\n")); out.concat(F("\r\n"));
_headLength = out.length(); _headLength = out.length();
@ -672,15 +675,16 @@ size_t AsyncProgmemResponse::_fillBuffer(uint8_t *data, size_t len){
* Response Stream (You can print/write/printf to it, up to the contentLen bytes) * Response Stream (You can print/write/printf to it, up to the contentLen bytes)
* */ * */
AsyncResponseStream::AsyncResponseStream(const String& contentType, size_t bufferSize) AsyncResponseStream::AsyncResponseStream(const String& contentType, size_t bufferSize){
{
_code = 200; _code = 200;
_contentLength = 0; _contentLength = 0;
_contentType = contentType; _contentType = contentType;
_content = std::unique_ptr<cbuf>(new cbuf(bufferSize)); //std::make_unique<cbuf>(bufferSize); _content = new cbuf(bufferSize);
} }
AsyncResponseStream::~AsyncResponseStream() = default; AsyncResponseStream::~AsyncResponseStream(){
delete _content;
}
size_t AsyncResponseStream::_fillBuffer(uint8_t *buf, size_t maxLen){ size_t AsyncResponseStream::_fillBuffer(uint8_t *buf, size_t maxLen){
return _content->read((char*)buf, maxLen); return _content->read((char*)buf, maxLen);