asyncwebserver optimizations

This commit is contained in:
Proddy
2024-03-10 21:15:34 +01:00
parent 18c5aaf598
commit 4e3eb3aeaa
22 changed files with 2154 additions and 1838 deletions

View File

@@ -63,7 +63,7 @@ class AsyncJsonResponse : public AsyncAbstractResponse {
~AsyncJsonResponse() {
}
JsonVariant & getRoot() {
JsonVariant getRoot() {
return _root;
}
bool _sourceValid() const {
@@ -108,7 +108,7 @@ class PrettyAsyncJsonResponse : public AsyncJsonResponse {
}
};
typedef std::function<void(AsyncWebServerRequest * request, JsonVariant & json)> ArJsonRequestHandlerFunction;
typedef std::function<void(AsyncWebServerRequest * request, JsonVariant json)> ArJsonRequestHandlerFunction;
class AsyncCallbackJsonWebHandler : public AsyncWebHandler {
private:
@@ -142,13 +142,15 @@ class AsyncCallbackJsonWebHandler : public AsyncWebHandler {
if (!_onRequest)
return false;
if (!(_method & request->method()))
WebRequestMethodComposite request_method = request->method();
if (!(_method & request_method))
return false;
if (_uri.length() && (_uri != request->url() && !request->url().startsWith(_uri + "/")))
return false;
if (!request->contentType().equalsIgnoreCase(JSON_MIMETYPE))
if (request_method != HTTP_GET && !request->contentType().equalsIgnoreCase(JSON_MIMETYPE))
return false;
request->addInterestingHeader("ANY");
@@ -156,18 +158,23 @@ class AsyncCallbackJsonWebHandler : public AsyncWebHandler {
}
virtual void handleRequest(AsyncWebServerRequest * request) override final {
if ((_username != "" && _password != "") && !request->authenticate(_username.c_str(), _password.c_str()))
return request->requestAuthentication();
if (_onRequest) {
JsonVariant json; // empty variant
if (request->_tempObject != NULL) {
if (request->method() == HTTP_GET) {
JsonVariant json;
_onRequest(request, json);
return;
} else if (request->_tempObject != NULL) {
JsonDocument jsonBuffer;
DeserializationError error = deserializeJson(jsonBuffer, (uint8_t *)(request->_tempObject));
if (!error) {
json = jsonBuffer.as<JsonVariant>();
JsonVariant json = jsonBuffer.as<JsonVariant>();
_onRequest(request, json);
return;
}
}
_onRequest(request, json);
request->send(_contentLength > _maxContentLength ? 413 : 400);
} else {
request->send(500);
}

View File

@@ -28,6 +28,8 @@
#include <vector>
#include "FS.h"
#include <ArduinoJson.h> // added by proddy
#include "StringArray.h"
#ifdef ESP32
@@ -65,26 +67,26 @@ class AsyncResponseStream;
#ifndef WEBSERVER_H
typedef enum {
HTTP_GET = 0b00000001,
HTTP_POST = 0b00000010,
HTTP_DELETE = 0b00000100,
HTTP_PUT = 0b00001000,
HTTP_PATCH = 0b00010000,
HTTP_HEAD = 0b00100000,
HTTP_OPTIONS = 0b01000000,
HTTP_ANY = 0b01111111,
HTTP_GET = 0b00000001,
HTTP_POST = 0b00000010,
HTTP_DELETE = 0b00000100,
HTTP_PUT = 0b00001000,
HTTP_PATCH = 0b00010000,
HTTP_HEAD = 0b00100000,
HTTP_OPTIONS = 0b01000000,
HTTP_ANY = 0b01111111,
} WebRequestMethod;
#endif
#ifndef HAVE_FS_FILE_OPEN_MODE
namespace fs {
class FileOpenMode {
public:
static const char *read;
static const char *write;
static const char *append;
};
class FileOpenMode {
public:
static const char * read;
static const char * write;
static const char * append;
};
}; // namespace fs
#else
#include "FileOpenMode.h"
#endif
@@ -92,7 +94,7 @@ namespace fs {
//if this value is returned when asked for data, packet will not be sent and you will be asked for data again
#define RESPONSE_TRY_AGAIN 0xFFFFFFFF
typedef uint8_t WebRequestMethodComposite;
typedef uint8_t WebRequestMethodComposite;
typedef std::function<void(void)> ArDisconnectHandler;
/*
@@ -104,17 +106,32 @@ class AsyncWebParameter {
String _name;
String _value;
size_t _size;
bool _isForm;
bool _isFile;
bool _isForm;
bool _isFile;
public:
AsyncWebParameter(const String& name, const String& value, bool form=false, bool file=false, size_t size=0): _name(name), _value(value), _size(size), _isForm(form), _isFile(file){}
const String& name() const { return _name; }
const String& value() const { return _value; }
size_t size() const { return _size; }
bool isPost() const { return _isForm; }
bool isFile() const { return _isFile; }
AsyncWebParameter(const String & name, const String & value, bool form = false, bool file = false, size_t size = 0)
: _name(name)
, _value(value)
, _size(size)
, _isForm(form)
, _isFile(file) {
}
const String & name() const {
return _name;
}
const String & value() const {
return _value;
}
size_t size() const {
return _size;
}
bool isPost() const {
return _isForm;
}
bool isFile() const {
return _isFile;
}
};
/*
@@ -127,23 +144,36 @@ class AsyncWebHeader {
String _value;
public:
AsyncWebHeader() = default;
AsyncWebHeader() = default;
AsyncWebHeader(const AsyncWebHeader &) = default;
AsyncWebHeader(const String& name, const String& value): _name(name), _value(value){}
AsyncWebHeader(const String& data): _name(), _value(){
if(!data) return;
int index = data.indexOf(':');
if (index < 0) return;
_name = data.substring(0, index);
_value = data.substring(index + 2);
AsyncWebHeader(const String & name, const String & value)
: _name(name)
, _value(value) {
}
AsyncWebHeader(const String & data)
: _name()
, _value() {
if (!data)
return;
int index = data.indexOf(':');
if (index < 0)
return;
_name = data.substring(0, index);
_value = data.substring(index + 2);
}
AsyncWebHeader &operator=(const AsyncWebHeader &) = default;
AsyncWebHeader & operator=(const AsyncWebHeader &) = default;
const String& name() const { return _name; }
const String& value() const { return _value; }
String toString() const { return _name + F(": ") + _value + F("\r\n"); }
const String & name() const {
return _name;
}
const String & value() const {
return _value;
}
String toString() const {
return _name + F(": ") + _value + F("\r\n");
}
};
/*
@@ -152,98 +182,117 @@ class AsyncWebHeader {
typedef enum { RCT_NOT_USED = -1, RCT_DEFAULT = 0, RCT_HTTP, RCT_WS, RCT_EVENT, RCT_MAX } RequestedConnectionType;
typedef std::function<size_t(uint8_t*, size_t, size_t)> AwsResponseFiller;
typedef std::function<String(const String&)> AwsTemplateProcessor;
typedef std::function<size_t(uint8_t *, size_t, size_t)> AwsResponseFiller;
typedef std::function<String(const String &)> AwsTemplateProcessor;
class AsyncWebServerRequest {
using File = fs::File;
using FS = fs::FS;
friend class AsyncWebServer;
friend class AsyncCallbackWebHandler;
private:
AsyncClient* _client;
AsyncWebServer* _server;
AsyncWebHandler* _handler;
AsyncWebServerResponse* _response;
std::vector<String> _interestingHeaders;
ArDisconnectHandler _onDisconnectfn;
using File = fs::File;
using FS = fs::FS;
friend class AsyncWebServer;
friend class AsyncCallbackWebHandler;
String _temp;
private:
AsyncClient * _client;
AsyncWebServer * _server;
AsyncWebHandler * _handler;
AsyncWebServerResponse * _response;
std::vector<String> _interestingHeaders;
ArDisconnectHandler _onDisconnectfn;
String _temp;
uint8_t _parseState;
uint8_t _version;
uint8_t _version;
WebRequestMethodComposite _method;
String _url;
String _host;
String _contentType;
String _boundary;
String _authorization;
RequestedConnectionType _reqconntype;
void _removeNotInterestingHeaders();
bool _isDigest;
bool _isMultipart;
bool _isPlainPost;
bool _expectingContinue;
size_t _contentLength;
size_t _parsedLength;
String _url;
String _host;
String _contentType;
String _boundary;
String _authorization;
RequestedConnectionType _reqconntype;
void _removeNotInterestingHeaders();
bool _isDigest;
bool _isMultipart;
bool _isPlainPost;
bool _expectingContinue;
size_t _contentLength;
size_t _parsedLength;
std::list<AsyncWebHeader> _headers;
std::list<AsyncWebHeader> _headers;
LinkedList<AsyncWebParameter *> _params;
std::vector<String> _pathParams;
std::vector<String> _pathParams;
uint8_t _multiParseState;
uint8_t _boundaryPosition;
size_t _itemStartIndex;
size_t _itemSize;
String _itemName;
String _itemFilename;
String _itemType;
String _itemValue;
uint8_t *_itemBuffer;
size_t _itemBufferIndex;
bool _itemIsFile;
uint8_t _multiParseState;
uint8_t _boundaryPosition;
size_t _itemStartIndex;
size_t _itemSize;
String _itemName;
String _itemFilename;
String _itemType;
String _itemValue;
uint8_t * _itemBuffer;
size_t _itemBufferIndex;
bool _itemIsFile;
void _onPoll();
void _onAck(size_t len, uint32_t time);
void _onError(int8_t error);
void _onTimeout(uint32_t time);
void _onDisconnect();
void _onData(void *buf, size_t len);
void _onData(void * buf, size_t len);
void _addParam(AsyncWebParameter*);
void _addPathParam(const char *param);
void _addParam(AsyncWebParameter *);
void _addPathParam(const char * param);
bool _parseReqHead();
bool _parseReqHeader();
void _parseLine();
void _parsePlainPostChar(uint8_t data);
void _parseMultipartPostByte(uint8_t data, bool last);
void _addGetParams(const String& params);
void _addGetParams(const String & params);
void _handleUploadStart();
void _handleUploadByte(uint8_t data, bool last);
void _handleUploadEnd();
public:
File _tempFile;
void *_tempObject;
File _tempFile;
void * _tempObject;
AsyncWebServerRequest(AsyncWebServer*, AsyncClient*);
AsyncWebServerRequest(AsyncWebServer *, AsyncClient *);
~AsyncWebServerRequest();
AsyncClient* client(){ return _client; }
uint8_t version() const { return _version; }
WebRequestMethodComposite method() const { return _method; }
const String& url() const { return _url; }
const String& host() const { return _host; }
const String& contentType() const { return _contentType; }
size_t contentLength() const { return _contentLength; }
bool multipart() const { return _isMultipart; }
const __FlashStringHelper *methodToString() const;
const __FlashStringHelper *requestedConnTypeToString() const;
RequestedConnectionType requestedConnType() const { return _reqconntype; }
AsyncClient * client() {
return _client;
}
uint8_t version() const {
return _version;
}
WebRequestMethodComposite method() const {
return _method;
}
const String & url() const {
return _url;
}
const String & host() const {
return _host;
}
const String & contentType() const {
return _contentType;
}
size_t contentLength() const {
return _contentLength;
}
bool multipart() const {
return _isMultipart;
}
const __FlashStringHelper * methodToString() const;
const __FlashStringHelper * requestedConnTypeToString() const;
RequestedConnectionType requestedConnType() const {
return _reqconntype;
}
bool isExpectedRequestedConnType(RequestedConnectionType erct1, RequestedConnectionType erct2 = RCT_NOT_USED, RequestedConnectionType erct3 = RCT_NOT_USED);
void onDisconnect (ArDisconnectHandler fn);
void onDisconnect(ArDisconnectHandler fn);
//hash is the string representation of:
// base64(user:pass) for basic or
@@ -252,76 +301,85 @@ class AsyncWebServerRequest {
bool authenticate(const char * username, const char * password, const char * realm = NULL, bool passwordIsHash = false);
void requestAuthentication(const char * realm = NULL, bool isDigest = true);
void setHandler(AsyncWebHandler *handler){ _handler = handler; }
void addInterestingHeader(const String& name);
void setHandler(AsyncWebHandler * handler) {
_handler = handler;
}
void addInterestingHeader(const String & name);
void redirect(const String& url);
void redirect(const String & url);
void send(AsyncWebServerResponse *response);
void send(int code, const String& contentType=String(), const String& content=String());
void send(FS &fs, const String& path, const String& contentType=String(), bool download=false, AwsTemplateProcessor callback=nullptr);
void send(File content, const String& path, const String& contentType=String(), bool download=false, AwsTemplateProcessor callback=nullptr);
void send(Stream &stream, const String& contentType, size_t len, AwsTemplateProcessor callback=nullptr);
void send(const String& contentType, size_t len, AwsResponseFiller callback, AwsTemplateProcessor templateCallback=nullptr);
void sendChunked(const String& contentType, AwsResponseFiller callback, AwsTemplateProcessor templateCallback=nullptr);
void send_P(int code, const String& contentType, const uint8_t * content, size_t len, AwsTemplateProcessor callback=nullptr);
void send_P(int code, const String& contentType, PGM_P content, AwsTemplateProcessor callback=nullptr);
void send(AsyncWebServerResponse * response);
void send(int code, const String & contentType = String(), const String & content = String());
void send(FS & fs, const String & path, const String & contentType = String(), bool download = false, AwsTemplateProcessor callback = nullptr);
void send(File content, const String & path, const String & contentType = String(), bool download = false, AwsTemplateProcessor callback = nullptr);
void send(Stream & stream, const String & contentType, size_t len, AwsTemplateProcessor callback = nullptr);
void send(const String & contentType, size_t len, AwsResponseFiller callback, AwsTemplateProcessor templateCallback = nullptr);
void sendChunked(const String & contentType, AwsResponseFiller callback, AwsTemplateProcessor templateCallback = nullptr);
void send_P(int code, const String & contentType, const uint8_t * content, size_t len, AwsTemplateProcessor callback = nullptr);
void send_P(int code, const String & contentType, PGM_P content, AwsTemplateProcessor callback = nullptr);
AsyncWebServerResponse *beginResponse(int code, const String& contentType=String(), const String& content=String());
AsyncWebServerResponse *beginResponse(FS &fs, const String& path, const String& contentType=String(), bool download=false, AwsTemplateProcessor callback=nullptr);
AsyncWebServerResponse *beginResponse(File content, const String& path, const String& contentType=String(), bool download=false, AwsTemplateProcessor callback=nullptr);
AsyncWebServerResponse *beginResponse(Stream &stream, const String& contentType, size_t len, AwsTemplateProcessor callback=nullptr);
AsyncWebServerResponse *beginResponse(const String& contentType, size_t len, AwsResponseFiller callback, AwsTemplateProcessor templateCallback=nullptr);
AsyncWebServerResponse *beginChunkedResponse(const String& contentType, AwsResponseFiller callback, AwsTemplateProcessor templateCallback=nullptr);
AsyncResponseStream *beginResponseStream(const String& contentType, size_t bufferSize=1460);
AsyncWebServerResponse *beginResponse_P(int code, const String& contentType, const uint8_t * content, size_t len, AwsTemplateProcessor callback=nullptr);
AsyncWebServerResponse *beginResponse_P(int code, const String& contentType, PGM_P content, AwsTemplateProcessor callback=nullptr);
AsyncWebServerResponse * beginResponse(int code, const String & contentType = String(), const String & content = String());
AsyncWebServerResponse *
beginResponse(FS & fs, const String & path, const String & contentType = String(), bool download = false, AwsTemplateProcessor callback = nullptr);
AsyncWebServerResponse *
beginResponse(File content, const String & path, const String & contentType = String(), bool download = false, AwsTemplateProcessor callback = nullptr);
AsyncWebServerResponse * beginResponse(Stream & stream, const String & contentType, size_t len, AwsTemplateProcessor callback = nullptr);
AsyncWebServerResponse * beginResponse(const String & contentType, size_t len, AwsResponseFiller callback, AwsTemplateProcessor templateCallback = nullptr);
AsyncWebServerResponse * beginChunkedResponse(const String & contentType, AwsResponseFiller callback, AwsTemplateProcessor templateCallback = nullptr);
AsyncResponseStream * beginResponseStream(const String & contentType, size_t bufferSize = 1460);
AsyncWebServerResponse * beginResponse_P(int code, const String & contentType, const uint8_t * content, size_t len, AwsTemplateProcessor callback = nullptr);
AsyncWebServerResponse * beginResponse_P(int code, const String & contentType, PGM_P content, AwsTemplateProcessor callback = nullptr);
size_t headers() const; // get header count
bool hasHeader(const String& name) const; // check if header exists
bool hasHeader(const __FlashStringHelper * data) const; // check if header exists
// added by proddy
AsyncWebServerResponse * beginResponse(const String & contentType, const uint8_t * content, size_t len);
AsyncWebHeader* getHeader(const String& name);
const AsyncWebHeader* getHeader(const String& name) const;
AsyncWebHeader* getHeader(const __FlashStringHelper * data);
const AsyncWebHeader* getHeader(const __FlashStringHelper * data) const;
AsyncWebHeader* getHeader(size_t num);
const AsyncWebHeader* getHeader(size_t num) const;
size_t headers() const; // get header count
bool hasHeader(const String & name) const; // check if header exists
bool hasHeader(const __FlashStringHelper * data) const; // check if header exists
size_t params() const; // get arguments count
bool hasParam(const String& name, bool post=false, bool file=false) const;
bool hasParam(const __FlashStringHelper * data, bool post=false, bool file=false) const;
AsyncWebHeader * getHeader(const String & name);
const AsyncWebHeader * getHeader(const String & name) const;
AsyncWebHeader * getHeader(const __FlashStringHelper * data);
const AsyncWebHeader * getHeader(const __FlashStringHelper * data) const;
AsyncWebHeader * getHeader(size_t num);
const AsyncWebHeader * getHeader(size_t num) const;
AsyncWebParameter* getParam(const String& name, bool post=false, bool file=false) const;
AsyncWebParameter* getParam(const __FlashStringHelper * data, bool post, bool file) const;
AsyncWebParameter* getParam(size_t num) const;
size_t params() const; // get arguments count
bool hasParam(const String & name, bool post = false, bool file = false) const;
bool hasParam(const __FlashStringHelper * data, bool post = false, bool file = false) const;
size_t args() const { return params(); } // get arguments count
const String& arg(const String& name) const; // get request argument value by name
const String& arg(const __FlashStringHelper * data) const; // get request argument value by F(name)
const String& arg(size_t i) const; // get request argument value by number
const String& argName(size_t i) const; // get request argument name by number
bool hasArg(const char* name) const; // check if argument exists
bool hasArg(const __FlashStringHelper * data) const; // check if F(argument) exists
AsyncWebParameter * getParam(const String & name, bool post = false, bool file = false) const;
AsyncWebParameter * getParam(const __FlashStringHelper * data, bool post, bool file) const;
AsyncWebParameter * getParam(size_t num) const;
const String& ASYNCWEBSERVER_REGEX_ATTRIBUTE pathArg(size_t i) const;
size_t args() const {
return params();
} // get arguments count
const String & arg(const String & name) const; // get request argument value by name
const String & arg(const __FlashStringHelper * data) const; // get request argument value by F(name)
const String & arg(size_t i) const; // get request argument value by number
const String & argName(size_t i) const; // get request argument name by number
bool hasArg(const char * name) const; // check if argument exists
bool hasArg(const __FlashStringHelper * data) const; // check if F(argument) exists
const String& header(const char* name) const;// get request header value by name
const String& header(const __FlashStringHelper * data) const;// get request header value by F(name)
const String& header(size_t i) const; // get request header value by number
const String& headerName(size_t i) const; // get request header name by number
String urlDecode(const String& text) const;
const String & ASYNCWEBSERVER_REGEX_ATTRIBUTE pathArg(size_t i) const;
const String & header(const char * name) const; // get request header value by name
const String & header(const __FlashStringHelper * data) const; // get request header value by F(name)
const String & header(size_t i) const; // get request header value by number
const String & headerName(size_t i) const; // get request header name by number
String urlDecode(const String & text) const;
};
/*
* FILTER :: Callback to filter AsyncWebRewrite and AsyncWebHandler (done by the Server)
* */
typedef std::function<bool(AsyncWebServerRequest *request)> ArRequestFilterFunction;
typedef std::function<bool(AsyncWebServerRequest * request)> ArRequestFilterFunction;
bool ON_STA_FILTER(AsyncWebServerRequest *request);
bool ON_STA_FILTER(AsyncWebServerRequest * request);
bool ON_AP_FILTER(AsyncWebServerRequest *request);
bool ON_AP_FILTER(AsyncWebServerRequest * request);
/*
* REWRITE :: One instance can be handle any Request (done by the Server)
@@ -329,25 +387,44 @@ bool ON_AP_FILTER(AsyncWebServerRequest *request);
class AsyncWebRewrite {
protected:
String _from;
String _toUrl;
String _params;
String _from;
String _toUrl;
String _params;
ArRequestFilterFunction _filter;
public:
AsyncWebRewrite(const char* from, const char* to): _from(from), _toUrl(to), _params(String()), _filter(NULL){
int index = _toUrl.indexOf('?');
if (index > 0) {
_params = _toUrl.substring(index +1);
_toUrl = _toUrl.substring(0, index);
}
AsyncWebRewrite(const char * from, const char * to)
: _from(from)
, _toUrl(to)
, _params(String())
, _filter(NULL) {
int index = _toUrl.indexOf('?');
if (index > 0) {
_params = _toUrl.substring(index + 1);
_toUrl = _toUrl.substring(0, index);
}
}
virtual ~AsyncWebRewrite() {
}
AsyncWebRewrite & setFilter(ArRequestFilterFunction fn) {
_filter = fn;
return *this;
}
bool filter(AsyncWebServerRequest * request) const {
return _filter == NULL || _filter(request);
}
const String & from(void) const {
return _from;
}
const String & toUrl(void) const {
return _toUrl;
}
const String & params(void) const {
return _params;
}
virtual bool match(AsyncWebServerRequest * request) {
return from() == request->url() && filter(request);
}
virtual ~AsyncWebRewrite(){}
AsyncWebRewrite& setFilter(ArRequestFilterFunction fn) { _filter = fn; return *this; }
bool filter(AsyncWebServerRequest *request) const { return _filter == NULL || _filter(request); }
const String& from(void) const { return _from; }
const String& toUrl(void) const { return _toUrl; }
const String& params(void) const { return _params; }
virtual bool match(AsyncWebServerRequest *request) { return from() == request->url() && filter(request); }
};
/*
@@ -357,78 +434,107 @@ class AsyncWebRewrite {
class AsyncWebHandler {
protected:
ArRequestFilterFunction _filter;
String _username;
String _password;
String _username;
String _password;
public:
AsyncWebHandler():_username(""), _password(""){}
AsyncWebHandler& setFilter(ArRequestFilterFunction fn) { _filter = fn; return *this; }
AsyncWebHandler& setAuthentication(const char *username, const char *password){ _username = String(username);_password = String(password); return *this; };
bool filter(AsyncWebServerRequest *request){ return _filter == NULL || _filter(request); }
virtual ~AsyncWebHandler(){}
virtual bool canHandle(AsyncWebServerRequest *request __attribute__((unused))){
return false;
AsyncWebHandler()
: _username("")
, _password("") {
}
AsyncWebHandler & setFilter(ArRequestFilterFunction fn) {
_filter = fn;
return *this;
}
AsyncWebHandler & setAuthentication(const char * username, const char * password) {
_username = String(username);
_password = String(password);
return *this;
};
bool filter(AsyncWebServerRequest * request) {
return _filter == NULL || _filter(request);
}
virtual ~AsyncWebHandler() {
}
virtual bool canHandle(AsyncWebServerRequest * request __attribute__((unused))) {
return false;
}
virtual void handleRequest(AsyncWebServerRequest * request __attribute__((unused))) {
}
virtual void handleUpload(AsyncWebServerRequest * request __attribute__((unused)),
const String & filename __attribute__((unused)),
size_t index __attribute__((unused)),
uint8_t * data __attribute__((unused)),
size_t len __attribute__((unused)),
bool final __attribute__((unused))) {
}
virtual void handleBody(AsyncWebServerRequest * request __attribute__((unused)),
uint8_t * data __attribute__((unused)),
size_t len __attribute__((unused)),
size_t index __attribute__((unused)),
size_t total __attribute__((unused))) {
}
virtual bool isRequestHandlerTrivial() {
return true;
}
virtual void handleRequest(AsyncWebServerRequest *request __attribute__((unused))){}
virtual void handleUpload(AsyncWebServerRequest *request __attribute__((unused)), const String& filename __attribute__((unused)), size_t index __attribute__((unused)), uint8_t *data __attribute__((unused)), size_t len __attribute__((unused)), bool final __attribute__((unused))){}
virtual void handleBody(AsyncWebServerRequest *request __attribute__((unused)), uint8_t *data __attribute__((unused)), size_t len __attribute__((unused)), size_t index __attribute__((unused)), size_t total __attribute__((unused))){}
virtual bool isRequestHandlerTrivial(){return true;}
};
/*
* RESPONSE :: One instance is created for each Request (attached by the Handler)
* */
typedef enum {
RESPONSE_SETUP, RESPONSE_HEADERS, RESPONSE_CONTENT, RESPONSE_WAIT_ACK, RESPONSE_END, RESPONSE_FAILED
} WebResponseState;
typedef enum { RESPONSE_SETUP, RESPONSE_HEADERS, RESPONSE_CONTENT, RESPONSE_WAIT_ACK, RESPONSE_END, RESPONSE_FAILED } WebResponseState;
class AsyncWebServerResponse {
protected:
int _code;
int _code;
std::list<AsyncWebHeader> _headers;
String _contentType;
size_t _contentLength;
bool _sendContentLength;
bool _chunked;
size_t _headLength;
size_t _sentLength;
size_t _ackedLength;
size_t _writtenLength;
WebResponseState _state;
const char* _responseCodeToString(int code);
public:
static const __FlashStringHelper *responseCodeToString(int code);
String _contentType;
size_t _contentLength;
bool _sendContentLength;
bool _chunked;
size_t _headLength;
size_t _sentLength;
size_t _ackedLength;
size_t _writtenLength;
WebResponseState _state;
const char * _responseCodeToString(int code);
public:
static const __FlashStringHelper * responseCodeToString(int code);
public:
AsyncWebServerResponse();
virtual ~AsyncWebServerResponse();
virtual void setCode(int code);
virtual void setContentLength(size_t len);
virtual void setContentType(const String& type);
virtual void addHeader(const String& name, const String& value);
virtual void setCode(int code);
virtual void setContentLength(size_t len);
virtual void setContentType(const String & type);
virtual void addHeader(const String & name, const String & value);
virtual String _assembleHead(uint8_t version);
virtual bool _started() const;
virtual bool _finished() const;
virtual bool _failed() const;
virtual bool _sourceValid() const;
virtual void _respond(AsyncWebServerRequest *request);
virtual size_t _ack(AsyncWebServerRequest *request, size_t len, uint32_t time);
virtual bool _started() const;
virtual bool _finished() const;
virtual bool _failed() const;
virtual bool _sourceValid() const;
virtual void _respond(AsyncWebServerRequest * request);
virtual size_t _ack(AsyncWebServerRequest * request, size_t len, uint32_t time);
};
/*
* SERVER :: One instance
* */
typedef std::function<void(AsyncWebServerRequest *request)> ArRequestHandlerFunction;
typedef std::function<void(AsyncWebServerRequest *request, const String& filename, size_t index, uint8_t *data, size_t len, bool final)> ArUploadHandlerFunction;
typedef std::function<void(AsyncWebServerRequest *request, uint8_t *data, size_t len, size_t index, size_t total)> ArBodyHandlerFunction;
typedef std::function<void(AsyncWebServerRequest * request)> ArRequestHandlerFunction;
typedef std::function<void(AsyncWebServerRequest * request, const String & filename, size_t index, uint8_t * data, size_t len, bool final)> ArUploadHandlerFunction;
typedef std::function<void(AsyncWebServerRequest * request, uint8_t * data, size_t len, size_t index, size_t total)> ArBodyHandlerFunction;
typedef std::function<void(AsyncWebServerRequest * request, JsonVariant json)> ArJsonRequestHandlerFunction; // added by proddy
class AsyncWebServer {
protected:
AsyncServer _server;
LinkedList<AsyncWebRewrite*> _rewrites;
LinkedList<AsyncWebHandler*> _handlers;
AsyncCallbackWebHandler* _catchAllHandler;
AsyncServer _server;
LinkedList<AsyncWebRewrite *> _rewrites;
LinkedList<AsyncWebHandler *> _handlers;
AsyncCallbackWebHandler * _catchAllHandler;
public:
AsyncWebServer(uint16_t port);
@@ -438,58 +544,65 @@ class AsyncWebServer {
void end();
#if ASYNC_TCP_SSL_ENABLED
void onSslFileRequest(AcSSlFileHandler cb, void* arg);
void beginSecure(const char *cert, const char *private_key_file, const char *password);
void onSslFileRequest(AcSSlFileHandler cb, void * arg);
void beginSecure(const char * cert, const char * private_key_file, const char * password);
#endif
AsyncWebRewrite& addRewrite(AsyncWebRewrite* rewrite);
bool removeRewrite(AsyncWebRewrite* rewrite);
AsyncWebRewrite& rewrite(const char* from, const char* to);
AsyncWebRewrite & addRewrite(AsyncWebRewrite * rewrite);
bool removeRewrite(AsyncWebRewrite * rewrite);
AsyncWebRewrite & rewrite(const char * from, const char * to);
AsyncWebHandler& addHandler(AsyncWebHandler* handler);
bool removeHandler(AsyncWebHandler* handler);
AsyncWebHandler & addHandler(AsyncWebHandler * handler);
bool removeHandler(AsyncWebHandler * handler);
AsyncCallbackWebHandler& on(const char* uri, ArRequestHandlerFunction onRequest);
AsyncCallbackWebHandler& on(const char* uri, WebRequestMethodComposite method, ArRequestHandlerFunction onRequest);
AsyncCallbackWebHandler& on(const char* uri, WebRequestMethodComposite method, ArRequestHandlerFunction onRequest, ArUploadHandlerFunction onUpload);
AsyncCallbackWebHandler& on(const char* uri, WebRequestMethodComposite method, ArRequestHandlerFunction onRequest, ArUploadHandlerFunction onUpload, ArBodyHandlerFunction onBody);
AsyncCallbackWebHandler & on(const char * uri, ArRequestHandlerFunction onRequest);
AsyncCallbackWebHandler & on(const char * uri, WebRequestMethodComposite method, ArRequestHandlerFunction onRequest);
AsyncCallbackWebHandler & on(const char * uri, WebRequestMethodComposite method, ArRequestHandlerFunction onRequest, ArUploadHandlerFunction onUpload);
AsyncCallbackWebHandler &
on(const char * uri, WebRequestMethodComposite method, ArRequestHandlerFunction onRequest, ArUploadHandlerFunction onUpload, ArBodyHandlerFunction onBody);
AsyncStaticWebHandler& serveStatic(const char* uri, fs::FS& fs, const char* path, const char* cache_control = NULL);
void on(const char * uri, ArJsonRequestHandlerFunction onRequest); // added by proddy
AsyncStaticWebHandler & serveStatic(const char * uri, fs::FS & fs, const char * path, const char * cache_control = NULL);
void onNotFound(ArRequestHandlerFunction fn); //called when handler is not assigned
void onFileUpload(ArUploadHandlerFunction fn); //handle file uploads
void onRequestBody(ArBodyHandlerFunction fn); //handle posts with plain body content (JSON often transmitted this way as a request)
void onRequestBody(ArBodyHandlerFunction fn); //handle posts with plain body content (JSON often transmitted this way as a request)
void reset(); //remove all writers and handlers, with onNotFound/onFileUpload/onRequestBody
void _handleDisconnect(AsyncWebServerRequest *request);
void _attachHandler(AsyncWebServerRequest *request);
void _rewriteRequest(AsyncWebServerRequest *request);
void _handleDisconnect(AsyncWebServerRequest * request);
void _attachHandler(AsyncWebServerRequest * request);
void _rewriteRequest(AsyncWebServerRequest * request);
};
class DefaultHeaders {
using headers_t = std::list<AsyncWebHeader>;
headers_t _headers;
using headers_t = std::list<AsyncWebHeader>;
headers_t _headers;
public:
DefaultHeaders() = default;
public:
DefaultHeaders() = default;
using ConstIterator = headers_t::const_iterator;
using ConstIterator = headers_t::const_iterator;
void addHeader(const String& name, const String& value){
_headers.emplace_back(name, value);
}
void addHeader(const String & name, const String & value) {
_headers.emplace_back(name, value);
}
ConstIterator begin() const { return _headers.begin(); }
ConstIterator end() const { return _headers.end(); }
ConstIterator begin() const {
return _headers.begin();
}
ConstIterator end() const {
return _headers.end();
}
DefaultHeaders(DefaultHeaders const &) = delete;
DefaultHeaders &operator=(DefaultHeaders const &) = delete;
DefaultHeaders(DefaultHeaders const &) = delete;
DefaultHeaders & operator=(DefaultHeaders const &) = delete;
static DefaultHeaders &Instance() {
static DefaultHeaders instance;
return instance;
}
static DefaultHeaders & Instance() {
static DefaultHeaders instance;
return instance;
}
};
#include "WebResponseImpl.h"

File diff suppressed because it is too large Load Diff

View File

@@ -31,34 +31,43 @@
// 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 {
private:
String _content;
public:
AsyncBasicResponse(int code, const String& contentType=String(), const String& content=String());
void _respond(AsyncWebServerRequest *request);
size_t _ack(AsyncWebServerRequest *request, size_t len, uint32_t time);
bool _sourceValid() const { return true; }
AsyncBasicResponse(int code, const String & contentType = String(), const String & content = String());
void _respond(AsyncWebServerRequest * request);
size_t _ack(AsyncWebServerRequest * request, size_t len, uint32_t time);
bool _sourceValid() const {
return true;
}
};
class AsyncAbstractResponse: public AsyncWebServerResponse {
class AsyncAbstractResponse : public AsyncWebServerResponse {
private:
String _head;
// Data is inserted into cache at begin().
// This is inefficient with vector, but if we use some other container,
// Data is inserted into cache at begin().
// This is inefficient with vector, but if we use some other container,
// we won't be able to access it as contiguous array of bytes when reading from it,
// so by gaining performance in one place, we'll lose it in another.
std::vector<uint8_t> _cache;
size_t _readDataFromCacheOrContent(uint8_t* data, const size_t len);
size_t _fillBufferAndProcessTemplates(uint8_t* buf, size_t maxLen);
size_t _readDataFromCacheOrContent(uint8_t * data, const size_t len);
size_t _fillBufferAndProcessTemplates(uint8_t * buf, size_t maxLen);
protected:
AwsTemplateProcessor _callback;
public:
AsyncAbstractResponse(AwsTemplateProcessor callback=nullptr);
void _respond(AsyncWebServerRequest *request);
size_t _ack(AsyncWebServerRequest *request, size_t len, uint32_t time);
bool _sourceValid() const { return false; }
virtual size_t _fillBuffer(uint8_t *buf __attribute__((unused)), size_t maxLen __attribute__((unused))) { return 0; }
AsyncAbstractResponse(AwsTemplateProcessor callback = nullptr);
void _respond(AsyncWebServerRequest * request);
size_t _ack(AsyncWebServerRequest * request, size_t len, uint32_t time);
bool _sourceValid() const {
return false;
}
virtual size_t _fillBuffer(uint8_t * buf __attribute__((unused)), size_t maxLen __attribute__((unused))) {
return 0;
}
};
#ifndef TEMPLATE_PLACEHOLDER
@@ -66,72 +75,105 @@ class AsyncAbstractResponse: public AsyncWebServerResponse {
#endif
#define TEMPLATE_PARAM_NAME_LENGTH 32
class AsyncFileResponse: public AsyncAbstractResponse {
using File = fs::File;
using FS = fs::FS;
class AsyncFileResponse : public AsyncAbstractResponse {
using File = fs::File;
using FS = fs::FS;
private:
File _content;
File _content;
String _path;
void _setContentType(const String& path);
void _setContentType(const String & path);
public:
AsyncFileResponse(FS &fs, const String& path, const String& contentType=String(), bool download=false, AwsTemplateProcessor callback=nullptr);
AsyncFileResponse(File content, const String& path, const String& contentType=String(), bool download=false, AwsTemplateProcessor callback=nullptr);
AsyncFileResponse(FS & fs, const String & path, const String & contentType = String(), bool download = false, AwsTemplateProcessor callback = nullptr);
AsyncFileResponse(File content, const String & path, const String & contentType = String(), bool download = false, AwsTemplateProcessor callback = nullptr);
~AsyncFileResponse();
bool _sourceValid() const { return !!(_content); }
virtual size_t _fillBuffer(uint8_t *buf, size_t maxLen) override;
bool _sourceValid() const {
return !!(_content);
}
virtual size_t _fillBuffer(uint8_t * buf, size_t maxLen) override;
};
class AsyncStreamResponse: public AsyncAbstractResponse {
class AsyncStreamResponse : public AsyncAbstractResponse {
private:
Stream *_content;
Stream * _content;
public:
AsyncStreamResponse(Stream &stream, const String& contentType, size_t len, AwsTemplateProcessor callback=nullptr);
bool _sourceValid() const { return !!(_content); }
virtual size_t _fillBuffer(uint8_t *buf, size_t maxLen) override;
AsyncStreamResponse(Stream & stream, const String & contentType, size_t len, AwsTemplateProcessor callback = nullptr);
bool _sourceValid() const {
return !!(_content);
}
virtual size_t _fillBuffer(uint8_t * buf, size_t maxLen) override;
};
class AsyncCallbackResponse: public AsyncAbstractResponse {
class AsyncCallbackResponse : public AsyncAbstractResponse {
private:
AwsResponseFiller _content;
size_t _filledLength;
size_t _filledLength;
public:
AsyncCallbackResponse(const String& contentType, size_t len, AwsResponseFiller callback, AwsTemplateProcessor templateCallback=nullptr);
bool _sourceValid() const { return !!(_content); }
virtual size_t _fillBuffer(uint8_t *buf, size_t maxLen) override;
AsyncCallbackResponse(const String & contentType, size_t len, AwsResponseFiller callback, AwsTemplateProcessor templateCallback = nullptr);
bool _sourceValid() const {
return !!(_content);
}
virtual size_t _fillBuffer(uint8_t * buf, size_t maxLen) override;
};
class AsyncChunkedResponse: public AsyncAbstractResponse {
class AsyncChunkedResponse : public AsyncAbstractResponse {
private:
AwsResponseFiller _content;
size_t _filledLength;
size_t _filledLength;
public:
AsyncChunkedResponse(const String& contentType, AwsResponseFiller callback, AwsTemplateProcessor templateCallback=nullptr);
bool _sourceValid() const { return !!(_content); }
virtual size_t _fillBuffer(uint8_t *buf, size_t maxLen) override;
AsyncChunkedResponse(const String & contentType, AwsResponseFiller callback, AwsTemplateProcessor templateCallback = nullptr);
bool _sourceValid() const {
return !!(_content);
}
virtual size_t _fillBuffer(uint8_t * buf, size_t maxLen) override;
};
class AsyncProgmemResponse: public AsyncAbstractResponse {
class AsyncProgmemResponse : public AsyncAbstractResponse {
private:
const uint8_t * _content;
size_t _readLength;
size_t _readLength;
public:
AsyncProgmemResponse(int code, const String& contentType, const uint8_t * content, size_t len, AwsTemplateProcessor callback=nullptr);
bool _sourceValid() const { return true; }
virtual size_t _fillBuffer(uint8_t *buf, size_t maxLen) override;
AsyncProgmemResponse(int code, const String & contentType, const uint8_t * content, size_t len, AwsTemplateProcessor callback = nullptr);
bool _sourceValid() const {
return true;
}
virtual size_t _fillBuffer(uint8_t * buf, size_t maxLen) override;
};
// added by proddy
class AsyncResponse : public AsyncAbstractResponse {
private:
const uint8_t * _content;
size_t _readLength;
public:
AsyncResponse(const String & contentType, const uint8_t * content, size_t len);
bool _sourceValid() const {
return true;
}
virtual size_t _fillBuffer(uint8_t * buf, size_t maxLen) override;
};
class cbuf;
class AsyncResponseStream: public AsyncAbstractResponse, public Print {
class AsyncResponseStream : public AsyncAbstractResponse, public Print {
private:
std::unique_ptr<cbuf> _content;
public:
AsyncResponseStream(const String& contentType, size_t bufferSize);
AsyncResponseStream(const String & contentType, size_t bufferSize);
~AsyncResponseStream();
bool _sourceValid() const { return (_state < RESPONSE_END); }
virtual size_t _fillBuffer(uint8_t *buf, size_t maxLen) override;
size_t write(const uint8_t *data, size_t len);
size_t write(uint8_t data);
bool _sourceValid() const {
return (_state < RESPONSE_END);
}
virtual size_t _fillBuffer(uint8_t * buf, size_t maxLen) override;
size_t write(const uint8_t * data, size_t len);
size_t write(uint8_t data);
using Print::write;
};

File diff suppressed because it is too large Load Diff

View File

@@ -20,179 +20,192 @@
*/
#include "ESPAsyncWebServer.h"
#include "WebHandlerImpl.h"
#include "AsyncJson.h"
bool ON_STA_FILTER(AsyncWebServerRequest *request) {
return WiFi.localIP() == request->client()->localIP();
bool ON_STA_FILTER(AsyncWebServerRequest * request) {
return WiFi.localIP() == request->client()->localIP();
}
bool ON_AP_FILTER(AsyncWebServerRequest *request) {
return WiFi.localIP() != request->client()->localIP();
bool ON_AP_FILTER(AsyncWebServerRequest * request) {
return WiFi.localIP() != request->client()->localIP();
}
#ifndef HAVE_FS_FILE_OPEN_MODE
const char *fs::FileOpenMode::read = "r";
const char *fs::FileOpenMode::write = "w";
const char *fs::FileOpenMode::append = "a";
const char * fs::FileOpenMode::read = "r";
const char * fs::FileOpenMode::write = "w";
const char * fs::FileOpenMode::append = "a";
#endif
AsyncWebServer::AsyncWebServer(uint16_t port)
: _server(port)
, _rewrites(LinkedList<AsyncWebRewrite*>([](AsyncWebRewrite* r){ delete r; }))
, _handlers(LinkedList<AsyncWebHandler*>([](AsyncWebHandler* h){ delete h; }))
{
_catchAllHandler = new AsyncCallbackWebHandler();
if(_catchAllHandler == NULL)
return;
_server.onClient([](void *s, AsyncClient* c){
if(c == NULL)
return;
c->setRxTimeout(3);
AsyncWebServerRequest *r = new AsyncWebServerRequest((AsyncWebServer*)s, c);
if(r == NULL){
c->close(true);
c->free();
delete c;
}
}, this);
: _server(port)
, _rewrites(LinkedList<AsyncWebRewrite *>([](AsyncWebRewrite * r) { delete r; }))
, _handlers(LinkedList<AsyncWebHandler *>([](AsyncWebHandler * h) { delete h; })) {
_catchAllHandler = new AsyncCallbackWebHandler();
if (_catchAllHandler == NULL)
return;
_server.onClient(
[](void * s, AsyncClient * c) {
if (c == NULL)
return;
c->setRxTimeout(3);
AsyncWebServerRequest * r = new AsyncWebServerRequest((AsyncWebServer *)s, c);
if (r == NULL) {
c->close(true);
c->free();
delete c;
}
},
this);
}
AsyncWebServer::~AsyncWebServer(){
reset();
end();
if(_catchAllHandler) delete _catchAllHandler;
AsyncWebServer::~AsyncWebServer() {
reset();
end();
if (_catchAllHandler)
delete _catchAllHandler;
}
AsyncWebRewrite& AsyncWebServer::addRewrite(AsyncWebRewrite* rewrite){
_rewrites.add(rewrite);
return *rewrite;
AsyncWebRewrite & AsyncWebServer::addRewrite(AsyncWebRewrite * rewrite) {
_rewrites.add(rewrite);
return *rewrite;
}
bool AsyncWebServer::removeRewrite(AsyncWebRewrite *rewrite){
return _rewrites.remove(rewrite);
bool AsyncWebServer::removeRewrite(AsyncWebRewrite * rewrite) {
return _rewrites.remove(rewrite);
}
AsyncWebRewrite& AsyncWebServer::rewrite(const char* from, const char* to){
return addRewrite(new AsyncWebRewrite(from, to));
AsyncWebRewrite & AsyncWebServer::rewrite(const char * from, const char * to) {
return addRewrite(new AsyncWebRewrite(from, to));
}
AsyncWebHandler& AsyncWebServer::addHandler(AsyncWebHandler* handler){
_handlers.add(handler);
return *handler;
AsyncWebHandler & AsyncWebServer::addHandler(AsyncWebHandler * handler) {
_handlers.add(handler);
return *handler;
}
bool AsyncWebServer::removeHandler(AsyncWebHandler *handler){
return _handlers.remove(handler);
bool AsyncWebServer::removeHandler(AsyncWebHandler * handler) {
return _handlers.remove(handler);
}
void AsyncWebServer::begin(){
_server.setNoDelay(true);
_server.begin();
void AsyncWebServer::begin() {
_server.setNoDelay(true);
_server.begin();
}
void AsyncWebServer::end(){
_server.end();
void AsyncWebServer::end() {
_server.end();
}
#if ASYNC_TCP_SSL_ENABLED
void AsyncWebServer::onSslFileRequest(AcSSlFileHandler cb, void* arg){
_server.onSslFileRequest(cb, arg);
void AsyncWebServer::onSslFileRequest(AcSSlFileHandler cb, void * arg) {
_server.onSslFileRequest(cb, arg);
}
void AsyncWebServer::beginSecure(const char *cert, const char *key, const char *password){
_server.beginSecure(cert, key, password);
void AsyncWebServer::beginSecure(const char * cert, const char * key, const char * password) {
_server.beginSecure(cert, key, password);
}
#endif
void AsyncWebServer::_handleDisconnect(AsyncWebServerRequest *request){
delete request;
void AsyncWebServer::_handleDisconnect(AsyncWebServerRequest * request) {
delete request;
}
void AsyncWebServer::_rewriteRequest(AsyncWebServerRequest *request){
for(const auto& r: _rewrites){
if (r->match(request)){
request->_url = r->toUrl();
request->_addGetParams(r->params());
void AsyncWebServer::_rewriteRequest(AsyncWebServerRequest * request) {
for (const auto & r : _rewrites) {
if (r->match(request)) {
request->_url = r->toUrl();
request->_addGetParams(r->params());
}
}
}
}
void AsyncWebServer::_attachHandler(AsyncWebServerRequest *request){
for(const auto& h: _handlers){
if (h->filter(request) && h->canHandle(request)){
request->setHandler(h);
return;
void AsyncWebServer::_attachHandler(AsyncWebServerRequest * request) {
for (const auto & h : _handlers) {
if (h->filter(request) && h->canHandle(request)) {
request->setHandler(h);
return;
}
}
}
request->addInterestingHeader(F("ANY"));
request->setHandler(_catchAllHandler);
request->addInterestingHeader(F("ANY"));
request->setHandler(_catchAllHandler);
}
AsyncCallbackWebHandler& AsyncWebServer::on(const char* uri, WebRequestMethodComposite method, ArRequestHandlerFunction onRequest, ArUploadHandlerFunction onUpload, ArBodyHandlerFunction onBody){
AsyncCallbackWebHandler* handler = new AsyncCallbackWebHandler();
handler->setUri(uri);
handler->setMethod(method);
handler->onRequest(onRequest);
handler->onUpload(onUpload);
handler->onBody(onBody);
addHandler(handler);
return *handler;
AsyncCallbackWebHandler & AsyncWebServer::on(const char * uri,
WebRequestMethodComposite method,
ArRequestHandlerFunction onRequest,
ArUploadHandlerFunction onUpload,
ArBodyHandlerFunction onBody) {
AsyncCallbackWebHandler * handler = new AsyncCallbackWebHandler();
handler->setUri(uri);
handler->setMethod(method);
handler->onRequest(onRequest);
handler->onUpload(onUpload);
handler->onBody(onBody);
addHandler(handler);
return *handler;
}
AsyncCallbackWebHandler& AsyncWebServer::on(const char* uri, WebRequestMethodComposite method, ArRequestHandlerFunction onRequest, ArUploadHandlerFunction onUpload){
AsyncCallbackWebHandler* handler = new AsyncCallbackWebHandler();
handler->setUri(uri);
handler->setMethod(method);
handler->onRequest(onRequest);
handler->onUpload(onUpload);
addHandler(handler);
return *handler;
AsyncCallbackWebHandler &
AsyncWebServer::on(const char * uri, WebRequestMethodComposite method, ArRequestHandlerFunction onRequest, ArUploadHandlerFunction onUpload) {
AsyncCallbackWebHandler * handler = new AsyncCallbackWebHandler();
handler->setUri(uri);
handler->setMethod(method);
handler->onRequest(onRequest);
handler->onUpload(onUpload);
addHandler(handler);
return *handler;
}
AsyncCallbackWebHandler& AsyncWebServer::on(const char* uri, WebRequestMethodComposite method, ArRequestHandlerFunction onRequest){
AsyncCallbackWebHandler* handler = new AsyncCallbackWebHandler();
handler->setUri(uri);
handler->setMethod(method);
handler->onRequest(onRequest);
addHandler(handler);
return *handler;
AsyncCallbackWebHandler & AsyncWebServer::on(const char * uri, WebRequestMethodComposite method, ArRequestHandlerFunction onRequest) {
AsyncCallbackWebHandler * handler = new AsyncCallbackWebHandler();
handler->setUri(uri);
handler->setMethod(method);
handler->onRequest(onRequest);
addHandler(handler);
return *handler;
}
AsyncCallbackWebHandler& AsyncWebServer::on(const char* uri, ArRequestHandlerFunction onRequest){
AsyncCallbackWebHandler* handler = new AsyncCallbackWebHandler();
handler->setUri(uri);
handler->onRequest(onRequest);
addHandler(handler);
return *handler;
AsyncCallbackWebHandler & AsyncWebServer::on(const char * uri, ArRequestHandlerFunction onRequest) {
AsyncCallbackWebHandler * handler = new AsyncCallbackWebHandler();
handler->setUri(uri);
handler->onRequest(onRequest);
addHandler(handler);
return *handler;
}
AsyncStaticWebHandler& AsyncWebServer::serveStatic(const char* uri, fs::FS& fs, const char* path, const char* cache_control){
AsyncStaticWebHandler* handler = new AsyncStaticWebHandler(uri, fs, path, cache_control);
addHandler(handler);
return *handler;
// added by proddy
void AsyncWebServer::on(const char * uri, ArJsonRequestHandlerFunction onRequest) {
auto * handler = new AsyncCallbackJsonWebHandler(uri, onRequest);
addHandler(handler);
}
void AsyncWebServer::onNotFound(ArRequestHandlerFunction fn){
_catchAllHandler->onRequest(fn);
AsyncStaticWebHandler & AsyncWebServer::serveStatic(const char * uri, fs::FS & fs, const char * path, const char * cache_control) {
AsyncStaticWebHandler * handler = new AsyncStaticWebHandler(uri, fs, path, cache_control);
addHandler(handler);
return *handler;
}
void AsyncWebServer::onFileUpload(ArUploadHandlerFunction fn){
_catchAllHandler->onUpload(fn);
void AsyncWebServer::onNotFound(ArRequestHandlerFunction fn) {
_catchAllHandler->onRequest(fn);
}
void AsyncWebServer::onRequestBody(ArBodyHandlerFunction fn){
_catchAllHandler->onBody(fn);
void AsyncWebServer::onFileUpload(ArUploadHandlerFunction fn) {
_catchAllHandler->onUpload(fn);
}
void AsyncWebServer::reset(){
_rewrites.free();
_handlers.free();
if (_catchAllHandler != NULL){
_catchAllHandler->onRequest(NULL);
_catchAllHandler->onUpload(NULL);
_catchAllHandler->onBody(NULL);
}
void AsyncWebServer::onRequestBody(ArBodyHandlerFunction fn) {
_catchAllHandler->onBody(fn);
}
void AsyncWebServer::reset() {
_rewrites.free();
_handlers.free();
if (_catchAllHandler != NULL) {
_catchAllHandler->onRequest(NULL);
_catchAllHandler->onUpload(NULL);
_catchAllHandler->onBody(NULL);
}
}

View File

@@ -1,12 +1,9 @@
#include "AuthenticationService.h"
AuthenticationService::AuthenticationService(AsyncWebServer * server, SecurityManager * securityManager)
: _securityManager(securityManager)
, _signInHandler(SIGN_IN_PATH, [this](AsyncWebServerRequest * request, JsonVariant json) { signIn(request, json); }) {
: _securityManager(securityManager) {
server->on(VERIFY_AUTHORIZATION_PATH, HTTP_GET, [this](AsyncWebServerRequest * request) { verifyAuthorization(request); });
_signInHandler.setMethod(HTTP_POST);
_signInHandler.setMaxContentLength(MAX_AUTHENTICATION_SIZE);
server->addHandler(&_signInHandler);
server->on(SIGN_IN_PATH, [this](AsyncWebServerRequest * request, JsonVariant json) { signIn(request, json); });
}
/**

View File

@@ -9,17 +9,13 @@
#define VERIFY_AUTHORIZATION_PATH "/rest/verifyAuthorization"
#define SIGN_IN_PATH "/rest/signIn"
#define MAX_AUTHENTICATION_SIZE 256
class AuthenticationService {
public:
AuthenticationService(AsyncWebServer * server, SecurityManager * securityManager);
private:
SecurityManager * _securityManager;
AsyncCallbackJsonWebHandler _signInHandler;
SecurityManager * _securityManager;
// endpoint functions
void signIn(AsyncWebServerRequest * request, JsonVariant json);
void verifyAuthorization(AsyncWebServerRequest * request);
};

View File

@@ -36,7 +36,8 @@ ESP8266React::ESP8266React(AsyncWebServer * server, FS * fs)
return request->send(304);
}
AsyncWebServerResponse * response = request->beginResponse_P(200, contentType, content, len);
AsyncWebServerResponse * response = request->beginResponse(contentType, content, len);
response->addHeader("Content-Encoding", "gzip");
// response->addHeader("Content-Encoding", "br"); // only works over HTTPS
// response->addHeader("Cache-Control", "public, immutable, max-age=31536000");

View File

@@ -17,8 +17,6 @@ class HttpEndpoint {
JsonStateUpdater<T> _stateUpdater;
StatefulService<T> * _statefulService;
AsyncCallbackJsonWebHandler * handler;
public:
HttpEndpoint(JsonStateReader<T> stateReader,
JsonStateUpdater<T> stateUpdater,
@@ -30,12 +28,10 @@ class HttpEndpoint {
: _stateReader(stateReader)
, _stateUpdater(stateUpdater)
, _statefulService(statefulService) {
// Create hander for both GET and POST endpoints
handler = new AsyncCallbackJsonWebHandler(servicePath,
securityManager->wrapCallback([this](AsyncWebServerRequest * request,
JsonVariant json) { handleRequest(request, json); },
authenticationPredicate));
server->addHandler(handler);
// Create handler for both GET and POST endpoints
server->on(servicePath.c_str(),
securityManager->wrapCallback([this](AsyncWebServerRequest * request, JsonVariant json) { handleRequest(request, json); },
authenticationPredicate));
}
protected:

View File

@@ -5,13 +5,10 @@
NTPSettingsService::NTPSettingsService(AsyncWebServer * server, FS * fs, SecurityManager * securityManager)
: _httpEndpoint(NTPSettings::read, NTPSettings::update, this, server, NTP_SETTINGS_SERVICE_PATH, securityManager)
, _fsPersistence(NTPSettings::read, NTPSettings::update, this, fs, NTP_SETTINGS_FILE)
, _timeHandler(TIME_PATH,
securityManager->wrapCallback([this](AsyncWebServerRequest * request, JsonVariant json) { configureTime(request, json); },
AuthenticationPredicates::IS_ADMIN))
, _connected(false) {
_timeHandler.setMethod(HTTP_POST);
_timeHandler.setMaxContentLength(MAX_TIME_SIZE);
server->addHandler(&_timeHandler);
server->on(TIME_PATH,
securityManager->wrapCallback([this](AsyncWebServerRequest * request, JsonVariant json) { configureTime(request, json); },
AuthenticationPredicates::IS_ADMIN));
WiFi.onEvent([this](WiFiEvent_t event, WiFiEventInfo_t info) { WiFiEvent(event); });
addUpdateHandler([this] { configureNTP(); }, false);

View File

@@ -24,9 +24,8 @@
#endif
#define NTP_SETTINGS_FILE "/config/ntpSettings.json"
#define NTP_SETTINGS_SERVICE_PATH "/rest/ntpSettings"
#define MAX_TIME_SIZE 256
#define NTP_SETTINGS_SERVICE_PATH "/rest/ntpSettings"
#define TIME_PATH "/rest/time"
class NTPSettings {
@@ -48,10 +47,9 @@ class NTPSettingsService : public StatefulService<NTPSettings> {
static void ntp_received(struct timeval * tv);
private:
HttpEndpoint<NTPSettings> _httpEndpoint;
FSPersistence<NTPSettings> _fsPersistence;
AsyncCallbackJsonWebHandler _timeHandler;
bool _connected;
HttpEndpoint<NTPSettings> _httpEndpoint;
FSPersistence<NTPSettings> _fsPersistence;
bool _connected;
void WiFiEvent(WiFiEvent_t event);
void configureNTP();

View File

@@ -213,6 +213,7 @@ class AsyncWebServerResponse {
typedef std::function<void(AsyncWebServerRequest * request)> ArRequestHandlerFunction;
typedef std::function<void(AsyncWebServerRequest * request, const String & filename, size_t index, uint8_t * data, size_t len, bool final)> ArUploadHandlerFunction;
typedef std::function<void(AsyncWebServerRequest * request, uint8_t * data, size_t len, size_t index, size_t total)> ArBodyHandlerFunction;
typedef std::function<void(AsyncWebServerRequest * request, JsonVariant json)> ArJsonRequestHandlerFunction; // added by proddy
class AsyncWebServer {
protected:
@@ -232,6 +233,7 @@ class AsyncWebServer {
}
void on(const char * uri, WebRequestMethodComposite method, ArRequestHandlerFunction onRequest){};
void on(const char * uri, ArJsonRequestHandlerFunction onRequest){}; // added by proddy
};

View File

@@ -1 +1 @@
#define EMSESP_APP_VERSION "3.6.5-dev.16"
#define EMSESP_APP_VERSION "3.6.5-dev.17"

View File

@@ -24,12 +24,11 @@ uint32_t WebAPIService::api_count_ = 0;
uint16_t WebAPIService::api_fails_ = 0;
WebAPIService::WebAPIService(AsyncWebServer * server, SecurityManager * securityManager)
: _securityManager(securityManager)
, _apiHandler(EMSESP_API_SERVICE_PATH, [this](AsyncWebServerRequest * request, JsonVariant json) { webAPIService_post(request, json); }) { // for POSTs
server->on(EMSESP_API_SERVICE_PATH, HTTP_GET, [this](AsyncWebServerRequest * request) { webAPIService_get(request); }); // for GETs
server->addHandler(&_apiHandler);
: _securityManager(securityManager) {
// API
server->on(EMSESP_API_SERVICE_PATH, [this](AsyncWebServerRequest * request, JsonVariant json) { webAPIService(request, json); });
// for settings
// settings
server->on(GET_SETTINGS_PATH,
HTTP_GET,
securityManager->wrapRequest([this](AsyncWebServerRequest * request) { getSettings(request); }, AuthenticationPredicates::IS_ADMIN));
@@ -47,31 +46,23 @@ WebAPIService::WebAPIService(AsyncWebServer * server, SecurityManager * security
securityManager->wrapRequest([this](AsyncWebServerRequest * request) { getEntities(request); }, AuthenticationPredicates::IS_ADMIN));
}
// HTTP GET
// GET /{device}
// GET /{device}/{entity}
void WebAPIService::webAPIService_get(AsyncWebServerRequest * request) {
// has no body JSON so create dummy as empty input object
JsonDocument input_doc;
JsonObject input = input_doc.to<JsonObject>();
parse(request, input);
}
// For HTTP POSTS with an optional JSON body
// HTTP_POST | HTTP_PUT | HTTP_PATCH
// POST /{device}[/{hc|id}][/{name}]
void WebAPIService::webAPIService_post(AsyncWebServerRequest * request, JsonVariant json) {
// POST|GET /{device}
// POST|GET /{device}/{entity}
void WebAPIService::webAPIService(AsyncWebServerRequest * request, JsonVariant json) {
JsonObject input;
// if no body then treat it as a secure GET
if (!json.is<JsonObject>()) {
webAPIService_get(request);
return;
if ((request->method() == HTTP_GET) || (!json.is<JsonObject>())) {
// HTTP GET
JsonDocument input_doc; // has no body JSON so create dummy as empty input object
input = input_doc.to<JsonObject>();
} else {
// HTTP_POST | HTTP_PUT | HTTP_PATCH
input = json.as<JsonObject>(); // extract values from the json. these will be used as default values
}
// extract values from the json. these will be used as default values
auto && input = json.as<JsonObject>();
parse(request, input);
}
// parse the URL looking for query or path parameters
// reporting back any errors
void WebAPIService::parse(AsyncWebServerRequest * request, JsonObject input) {
@@ -84,7 +75,7 @@ void WebAPIService::parse(AsyncWebServerRequest * request, JsonObject input) {
// check for query parameters first, the old style from v2
// api?device={device}&cmd={name}&data={value}&id={hc}
if (request->url() == "/api") {
if (request->url() == EMSESP_API_SERVICE_PATH) {
// get the device
if (request->hasParam(F_(device))) {
input["device"] = request->getParam(F_(device))->value().c_str();

View File

@@ -20,6 +20,7 @@
#define WebAPIService_h
#define EMSESP_API_SERVICE_PATH "/api"
#define GET_SETTINGS_PATH "/rest/getSettings"
#define GET_CUSTOMIZATIONS_PATH "/rest/getCustomizations"
#define GET_SCHEDULE_PATH "/rest/getSchedule"
@@ -31,8 +32,7 @@ class WebAPIService {
public:
WebAPIService(AsyncWebServer * server, SecurityManager * securityManager);
void webAPIService_post(AsyncWebServerRequest * request, JsonVariant json); // for POSTs
void webAPIService_get(AsyncWebServerRequest * request); // for GETs
void webAPIService(AsyncWebServerRequest * request, JsonVariant json);
static uint32_t api_count() {
return api_count_;
@@ -43,14 +43,12 @@ class WebAPIService {
}
private:
SecurityManager * _securityManager;
AsyncCallbackJsonWebHandler _apiHandler; // for POSTs
SecurityManager * _securityManager;
static uint32_t api_count_;
static uint16_t api_fails_;
void parse(AsyncWebServerRequest * request, JsonObject input);
void getSettings(AsyncWebServerRequest * request);
void getCustomizations(AsyncWebServerRequest * request);
void getSchedule(AsyncWebServerRequest * request);

View File

@@ -23,10 +23,7 @@ namespace emsesp {
bool WebCustomization::_start = true;
WebCustomizationService::WebCustomizationService(AsyncWebServer * server, FS * fs, SecurityManager * securityManager)
: _fsPersistence(WebCustomization::read, WebCustomization::update, this, fs, EMSESP_CUSTOMIZATION_FILE)
, _masked_entities_handler(CUSTOMIZATION_ENTITIES_PATH,
securityManager->wrapCallback([this](AsyncWebServerRequest * request, JsonVariant json) { customization_entities(request, json); },
AuthenticationPredicates::IS_AUTHENTICATED)) {
: _fsPersistence(WebCustomization::read, WebCustomization::update, this, fs, EMSESP_CUSTOMIZATION_FILE) {
server->on(DEVICE_ENTITIES_PATH,
HTTP_GET,
securityManager->wrapRequest([this](AsyncWebServerRequest * request) { device_entities(request); }, AuthenticationPredicates::IS_AUTHENTICATED));
@@ -39,9 +36,9 @@ WebCustomizationService::WebCustomizationService(AsyncWebServer * server, FS * f
HTTP_POST,
securityManager->wrapRequest([this](AsyncWebServerRequest * request) { reset_customization(request); }, AuthenticationPredicates::IS_ADMIN));
_masked_entities_handler.setMethod(HTTP_POST);
_masked_entities_handler.setMaxContentLength(2048);
server->addHandler(&_masked_entities_handler);
server->on(CUSTOMIZATION_ENTITIES_PATH,
securityManager->wrapCallback([this](AsyncWebServerRequest * request, JsonVariant json) { customization_entities(request, json); },
AuthenticationPredicates::IS_AUTHENTICATED));
}
// this creates the customization file, saving it to the FS

View File

@@ -101,8 +101,6 @@ class WebCustomizationService : public StatefulService<WebCustomization> {
// POST
void customization_entities(AsyncWebServerRequest * request, JsonVariant json);
void reset_customization(AsyncWebServerRequest * request); // command
AsyncCallbackJsonWebHandler _masked_entities_handler;
};
} // namespace emsesp

View File

@@ -21,16 +21,18 @@
namespace emsesp {
WebDataService::WebDataService(AsyncWebServer * server, SecurityManager * securityManager)
: _write_value_handler(WRITE_DEVICE_VALUE_SERVICE_PATH,
securityManager->wrapCallback([this](AsyncWebServerRequest * request, JsonVariant json) { write_device_value(request, json); },
AuthenticationPredicates::IS_ADMIN))
, _write_temperature_handler(WRITE_TEMPERATURE_SENSOR_SERVICE_PATH,
securityManager->wrapCallback([this](AsyncWebServerRequest * request,
JsonVariant json) { write_temperature_sensor(request, json); },
AuthenticationPredicates::IS_ADMIN))
, _write_analog_handler(WRITE_ANALOG_SENSOR_SERVICE_PATH,
securityManager->wrapCallback([this](AsyncWebServerRequest * request, JsonVariant json) { write_analog_sensor(request, json); },
AuthenticationPredicates::IS_ADMIN)) {
{
// write endpoints
server->on(WRITE_DEVICE_VALUE_SERVICE_PATH,
securityManager->wrapCallback([this](AsyncWebServerRequest * request, JsonVariant json) { write_device_value(request, json); },
AuthenticationPredicates::IS_ADMIN));
server->on(WRITE_TEMPERATURE_SENSOR_SERVICE_PATH,
securityManager->wrapCallback([this](AsyncWebServerRequest * request, JsonVariant json) { write_temperature_sensor(request, json); },
AuthenticationPredicates::IS_ADMIN));
server->on(WRITE_ANALOG_SENSOR_SERVICE_PATH,
securityManager->wrapCallback([this](AsyncWebServerRequest * request, JsonVariant json) { write_analog_sensor(request, json); },
AuthenticationPredicates::IS_ADMIN));
// GET's
server->on(DEVICE_DATA_SERVICE_PATH,
HTTP_GET,
@@ -49,19 +51,6 @@ WebDataService::WebDataService(AsyncWebServer * server, SecurityManager * securi
server->on(SCAN_DEVICES_SERVICE_PATH,
HTTP_POST,
securityManager->wrapRequest([this](AsyncWebServerRequest * request) { scan_devices(request); }, AuthenticationPredicates::IS_ADMIN));
_write_value_handler.setMethod(HTTP_POST);
_write_value_handler.setMaxContentLength(256);
server->addHandler(&_write_value_handler);
_write_temperature_handler.setMethod(HTTP_POST);
_write_temperature_handler.setMaxContentLength(256);
server->addHandler(&_write_temperature_handler);
_write_analog_handler.setMethod(HTTP_POST);
_write_analog_handler.setMaxContentLength(256);
server->addHandler(&_write_analog_handler);
}
// scan devices service

View File

@@ -51,8 +51,6 @@ class WebDataService {
void write_temperature_sensor(AsyncWebServerRequest * request, JsonVariant json);
void write_analog_sensor(AsyncWebServerRequest * request, JsonVariant json);
void scan_devices(AsyncWebServerRequest * request); // command
AsyncCallbackJsonWebHandler _write_value_handler, _write_temperature_handler, _write_analog_handler;
};
} // namespace emsesp

View File

@@ -21,17 +21,16 @@
namespace emsesp {
WebLogService::WebLogService(AsyncWebServer * server, SecurityManager * securityManager)
: events_(EVENT_SOURCE_LOG_PATH)
, setValues_(LOG_SETTINGS_PATH, [this](AsyncWebServerRequest * request, JsonVariant json) { setValues(request, json); }) {
events_.setFilter(securityManager->filterRequest(AuthenticationPredicates::IS_ADMIN));
: events_(EVENT_SOURCE_LOG_PATH) {
// set settings
server->on(LOG_SETTINGS_PATH, [this](AsyncWebServerRequest * request, JsonVariant json) { setValues(request, json); });
// get settings
server->on(LOG_SETTINGS_PATH, HTTP_GET, [this](AsyncWebServerRequest * request) { getValues(request); });
// for bring back the whole log - is a command, hence a POST
server->on(FETCH_LOG_PATH, HTTP_POST, [this](AsyncWebServerRequest * request) { fetchLog(request); });
server->addHandler(&setValues_);
events_.setFilter(securityManager->filterRequest(AuthenticationPredicates::IS_ADMIN));
server->addHandler(&events_);
}

View File

@@ -66,8 +66,6 @@ class WebLogService : public uuid::log::Handler {
void setValues(AsyncWebServerRequest * request, JsonVariant json);
AsyncCallbackJsonWebHandler setValues_; // for POSTs
uint64_t last_transmit_ = 0; // Last transmit time
size_t maximum_log_messages_ = MAX_LOG_MESSAGES; // Maximum number of log messages to buffer before they are output
size_t limit_log_messages_ = 1; // dynamic limit