Compare commits
1 Commits
feature/vo
...
patches
Author | SHA1 | Date | |
---|---|---|---|
76648f4c2d |
@ -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"
|
||||||
},
|
},
|
||||||
{
|
{
|
@ -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){
|
||||||
|
@ -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
@ -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
|
||||||
|
@ -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_
|
@ -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;
|
||||||
|
@ -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_ */
|
||||||
|
@ -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);
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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();
|
||||||
|
@ -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);
|
||||||
|
Reference in New Issue
Block a user