Merge pull request #1654 from proddy/dev

cleanup and making asyncWS cleaner
This commit is contained in:
Proddy
2024-03-10 21:17:21 +01:00
committed by GitHub
29 changed files with 2170 additions and 1953 deletions

6
.gitignore vendored
View File

@@ -1,8 +1,5 @@
# vscode # vscode
.vscode/c_cpp_properties.json .vscode/*
.vscode/extensions.json
.vscode/launch.json
.vscode/settings.json
# c++ compiling # c++ compiling
.clang_complete .clang_complete
@@ -60,3 +57,4 @@ bw-output/
# testing # testing
emsesp emsesp

View File

@@ -2,8 +2,6 @@
// See http://go.microsoft.com/fwlink/?LinkId=827846 // See http://go.microsoft.com/fwlink/?LinkId=827846
// for the documentation about the extensions.json format // for the documentation about the extensions.json format
"recommendations": [ "recommendations": [
"dbaeumer.vscode-eslint",
"esbenp.prettier-vscode",
"platformio.platformio-ide" "platformio.platformio-ide"
], ],
"unwantedRecommendations": [ "unwantedRecommendations": [

88
.vscode/settings.json vendored
View File

@@ -1,88 +0,0 @@
{
"search.exclude": {
"**/.yarn": true,
"**/.pnp.*": true
},
"editor.codeActionsOnSave": {
"source.fixAll": "explicit"
},
"eslint.nodePath": "interface/.yarn/sdks",
"eslint.workingDirectories": ["interface"],
"prettier.prettierPath": "",
"typescript.enablePromptUseWorkspaceTsdk": true,
"files.associations": {
"*.tsx": "typescriptreact",
"*.tcc": "cpp",
"optional": "cpp",
"istream": "cpp",
"ostream": "cpp",
"ratio": "cpp",
"system_error": "cpp",
"array": "cpp",
"functional": "cpp",
"regex": "cpp",
"tuple": "cpp",
"type_traits": "cpp",
"utility": "cpp",
"string": "cpp",
"string_view": "cpp",
"atomic": "cpp",
"bitset": "cpp",
"cctype": "cpp",
"chrono": "cpp",
"clocale": "cpp",
"cmath": "cpp",
"condition_variable": "cpp",
"cstdarg": "cpp",
"cstddef": "cpp",
"cstdint": "cpp",
"cstdio": "cpp",
"cstdlib": "cpp",
"cstring": "cpp",
"ctime": "cpp",
"cwchar": "cpp",
"cwctype": "cpp",
"deque": "cpp",
"list": "cpp",
"unordered_map": "cpp",
"unordered_set": "cpp",
"vector": "cpp",
"exception": "cpp",
"algorithm": "cpp",
"iterator": "cpp",
"map": "cpp",
"memory": "cpp",
"memory_resource": "cpp",
"numeric": "cpp",
"random": "cpp",
"set": "cpp",
"fstream": "cpp",
"initializer_list": "cpp",
"iomanip": "cpp",
"iosfwd": "cpp",
"iostream": "cpp",
"limits": "cpp",
"mutex": "cpp",
"new": "cpp",
"sstream": "cpp",
"stdexcept": "cpp",
"streambuf": "cpp",
"thread": "cpp",
"cinttypes": "cpp",
"typeinfo": "cpp"
},
"todo-tree.filtering.excludeGlobs": [
"**/vendor/**",
"**/node_modules/**",
"**/dist/**",
"**/bower_components/**",
"**/build/**",
"**/.vscode/**",
"**/.github/**",
"**/_output/**",
"**/*.min.*",
"**/*.map",
"**/ArduinoJson/**"
],
"cSpell.enableFiletypes": ["!cpp"]
}

18
.vscode/tasks.json vendored
View File

@@ -1,18 +0,0 @@
{
// See https://go.microsoft.com/fwlink/?LinkId=733558
// for the documentation about the tasks.json format
"version": "2.0.0",
"tasks": [
{
"type": "shell",
"label": "build standalone emsesp",
"command": "make",
"args": [],
"problemMatcher": ["$gcc"],
"group": {
"kind": "build",
"isDefault": true
}
}
]
}

View File

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

View File

@@ -28,6 +28,8 @@
#include <vector> #include <vector>
#include "FS.h" #include "FS.h"
#include <ArduinoJson.h> // added by proddy
#include "StringArray.h" #include "StringArray.h"
#ifdef ESP32 #ifdef ESP32
@@ -84,7 +86,7 @@ namespace fs {
static const char * write; static const char * write;
static const char * append; static const char * append;
}; };
}; }; // namespace fs
#else #else
#include "FileOpenMode.h" #include "FileOpenMode.h"
#endif #endif
@@ -108,13 +110,28 @@ class AsyncWebParameter {
bool _isFile; bool _isFile;
public: public:
AsyncWebParameter(const String & name, const String & value, bool form = false, bool file = false, size_t size = 0)
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){} : _name(name)
const String& name() const { return _name; } , _value(value)
const String& value() const { return _value; } , _size(size)
size_t size() const { return _size; } , _isForm(form)
bool isPost() const { return _isForm; } , _isFile(file) {
bool isFile() const { return _isFile; } }
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;
}
}; };
/* /*
@@ -130,20 +147,33 @@ class AsyncWebHeader {
AsyncWebHeader() = default; AsyncWebHeader() = default;
AsyncWebHeader(const AsyncWebHeader &) = default; AsyncWebHeader(const AsyncWebHeader &) = default;
AsyncWebHeader(const String& name, const String& value): _name(name), _value(value){} AsyncWebHeader(const String & name, const String & value)
AsyncWebHeader(const String& data): _name(), _value(){ : _name(name)
if(!data) return; , _value(value) {
}
AsyncWebHeader(const String & data)
: _name()
, _value() {
if (!data)
return;
int index = data.indexOf(':'); int index = data.indexOf(':');
if (index < 0) return; if (index < 0)
return;
_name = data.substring(0, index); _name = data.substring(0, index);
_value = data.substring(index + 2); _value = data.substring(index + 2);
} }
AsyncWebHeader & operator=(const AsyncWebHeader &) = default; AsyncWebHeader & operator=(const AsyncWebHeader &) = default;
const String& name() const { return _name; } const String & name() const {
const String& value() const { return _value; } return _name;
String toString() const { return _name + F(": ") + _value + F("\r\n"); } }
const String & value() const {
return _value;
}
String toString() const {
return _name + F(": ") + _value + F("\r\n");
}
}; };
/* /*
@@ -160,6 +190,7 @@ class AsyncWebServerRequest {
using FS = fs::FS; using FS = fs::FS;
friend class AsyncWebServer; friend class AsyncWebServer;
friend class AsyncCallbackWebHandler; friend class AsyncCallbackWebHandler;
private: private:
AsyncClient * _client; AsyncClient * _client;
AsyncWebServer * _server; AsyncWebServer * _server;
@@ -231,17 +262,35 @@ class AsyncWebServerRequest {
AsyncWebServerRequest(AsyncWebServer *, AsyncClient *); AsyncWebServerRequest(AsyncWebServer *, AsyncClient *);
~AsyncWebServerRequest(); ~AsyncWebServerRequest();
AsyncClient* client(){ return _client; } AsyncClient * client() {
uint8_t version() const { return _version; } return _client;
WebRequestMethodComposite method() const { return _method; } }
const String& url() const { return _url; } uint8_t version() const {
const String& host() const { return _host; } return _version;
const String& contentType() const { return _contentType; } }
size_t contentLength() const { return _contentLength; } WebRequestMethodComposite method() const {
bool multipart() const { return _isMultipart; } 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 * methodToString() const;
const __FlashStringHelper * requestedConnTypeToString() const; const __FlashStringHelper * requestedConnTypeToString() const;
RequestedConnectionType requestedConnType() const { return _reqconntype; } RequestedConnectionType requestedConnType() const {
return _reqconntype;
}
bool isExpectedRequestedConnType(RequestedConnectionType erct1, RequestedConnectionType erct2 = RCT_NOT_USED, RequestedConnectionType erct3 = RCT_NOT_USED); bool isExpectedRequestedConnType(RequestedConnectionType erct1, RequestedConnectionType erct2 = RCT_NOT_USED, RequestedConnectionType erct3 = RCT_NOT_USED);
void onDisconnect(ArDisconnectHandler fn); void onDisconnect(ArDisconnectHandler fn);
@@ -252,7 +301,9 @@ class AsyncWebServerRequest {
bool authenticate(const char * username, const char * password, const char * realm = NULL, bool passwordIsHash = false); 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 requestAuthentication(const char * realm = NULL, bool isDigest = true);
void setHandler(AsyncWebHandler *handler){ _handler = handler; } void setHandler(AsyncWebHandler * handler) {
_handler = handler;
}
void addInterestingHeader(const String & name); void addInterestingHeader(const String & name);
void redirect(const String & url); void redirect(const String & url);
@@ -268,8 +319,10 @@ class AsyncWebServerRequest {
void send_P(int code, const String & contentType, PGM_P content, 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(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 *
AsyncWebServerResponse *beginResponse(File content, const String& path, const String& contentType=String(), bool download=false, AwsTemplateProcessor callback=nullptr); 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(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 * beginResponse(const String & contentType, size_t len, AwsResponseFiller callback, AwsTemplateProcessor templateCallback = nullptr);
AsyncWebServerResponse * beginChunkedResponse(const String & contentType, AwsResponseFiller callback, AwsTemplateProcessor templateCallback = nullptr); AsyncWebServerResponse * beginChunkedResponse(const String & contentType, AwsResponseFiller callback, AwsTemplateProcessor templateCallback = nullptr);
@@ -277,6 +330,9 @@ class AsyncWebServerRequest {
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, 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_P(int code, const String & contentType, PGM_P content, AwsTemplateProcessor callback = nullptr);
// added by proddy
AsyncWebServerResponse * beginResponse(const String & contentType, const uint8_t * content, size_t len);
size_t headers() const; // get header count size_t headers() const; // get header count
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
@@ -296,7 +352,9 @@ class AsyncWebServerRequest {
AsyncWebParameter * getParam(const __FlashStringHelper * data, bool post, bool file) const; AsyncWebParameter * getParam(const __FlashStringHelper * data, bool post, bool file) const;
AsyncWebParameter * getParam(size_t num) const; AsyncWebParameter * getParam(size_t num) const;
size_t args() const { return params(); } // get arguments count 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 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(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 & arg(size_t i) const; // get request argument value by number
@@ -333,21 +391,40 @@ class AsyncWebRewrite {
String _toUrl; String _toUrl;
String _params; String _params;
ArRequestFilterFunction _filter; ArRequestFilterFunction _filter;
public: public:
AsyncWebRewrite(const char* from, const char* to): _from(from), _toUrl(to), _params(String()), _filter(NULL){ AsyncWebRewrite(const char * from, const char * to)
: _from(from)
, _toUrl(to)
, _params(String())
, _filter(NULL) {
int index = _toUrl.indexOf('?'); int index = _toUrl.indexOf('?');
if (index > 0) { if (index > 0) {
_params = _toUrl.substring(index + 1); _params = _toUrl.substring(index + 1);
_toUrl = _toUrl.substring(0, index); _toUrl = _toUrl.substring(0, index);
} }
} }
virtual ~AsyncWebRewrite(){} virtual ~AsyncWebRewrite() {
AsyncWebRewrite& setFilter(ArRequestFilterFunction fn) { _filter = fn; return *this; } }
bool filter(AsyncWebServerRequest *request) const { return _filter == NULL || _filter(request); } AsyncWebRewrite & setFilter(ArRequestFilterFunction fn) {
const String& from(void) const { return _from; } _filter = fn;
const String& toUrl(void) const { return _toUrl; } return *this;
const String& params(void) const { return _params; } }
virtual bool match(AsyncWebServerRequest *request) { return from() == request->url() && filter(request); } 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);
}
}; };
/* /*
@@ -359,28 +436,54 @@ class AsyncWebHandler {
ArRequestFilterFunction _filter; ArRequestFilterFunction _filter;
String _username; String _username;
String _password; String _password;
public: public:
AsyncWebHandler():_username(""), _password(""){} AsyncWebHandler()
AsyncWebHandler& setFilter(ArRequestFilterFunction fn) { _filter = fn; return *this; } : _username("")
AsyncWebHandler& setAuthentication(const char *username, const char *password){ _username = String(username);_password = String(password); return *this; }; , _password("") {
bool filter(AsyncWebServerRequest *request){ return _filter == NULL || _filter(request); } }
virtual ~AsyncWebHandler(){} 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))) { virtual bool canHandle(AsyncWebServerRequest * request __attribute__((unused))) {
return false; return false;
} }
virtual void handleRequest(AsyncWebServerRequest *request __attribute__((unused))){} 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 void handleUpload(AsyncWebServerRequest * request __attribute__((unused)),
virtual bool isRequestHandlerTrivial(){return true;} 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) * RESPONSE :: One instance is created for each Request (attached by the Handler)
* */ * */
typedef enum { typedef enum { RESPONSE_SETUP, RESPONSE_HEADERS, RESPONSE_CONTENT, RESPONSE_WAIT_ACK, RESPONSE_END, RESPONSE_FAILED } WebResponseState;
RESPONSE_SETUP, RESPONSE_HEADERS, RESPONSE_CONTENT, RESPONSE_WAIT_ACK, RESPONSE_END, RESPONSE_FAILED
} WebResponseState;
class AsyncWebServerResponse { class AsyncWebServerResponse {
protected: protected:
@@ -396,6 +499,7 @@ class AsyncWebServerResponse {
size_t _writtenLength; size_t _writtenLength;
WebResponseState _state; WebResponseState _state;
const char * _responseCodeToString(int code); const char * _responseCodeToString(int code);
public: public:
static const __FlashStringHelper * responseCodeToString(int code); static const __FlashStringHelper * responseCodeToString(int code);
@@ -423,6 +527,8 @@ typedef std::function<void(AsyncWebServerRequest *request)> ArRequestHandlerFunc
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, 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, 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 { class AsyncWebServer {
protected: protected:
AsyncServer _server; AsyncServer _server;
@@ -452,7 +558,10 @@ class AsyncWebServer {
AsyncCallbackWebHandler & on(const char * uri, ArRequestHandlerFunction onRequest); 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);
AsyncCallbackWebHandler & on(const char * uri, WebRequestMethodComposite method, ArRequestHandlerFunction onRequest, ArUploadHandlerFunction onUpload); 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, WebRequestMethodComposite method, ArRequestHandlerFunction onRequest, ArUploadHandlerFunction onUpload, ArBodyHandlerFunction onBody);
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); AsyncStaticWebHandler & serveStatic(const char * uri, fs::FS & fs, const char * path, const char * cache_control = NULL);
@@ -480,8 +589,12 @@ public:
_headers.emplace_back(name, value); _headers.emplace_back(name, value);
} }
ConstIterator begin() const { return _headers.begin(); } ConstIterator begin() const {
ConstIterator end() const { return _headers.end(); } return _headers.begin();
}
ConstIterator end() const {
return _headers.end();
}
DefaultHeaders(DefaultHeaders const &) = delete; DefaultHeaders(DefaultHeaders const &) = delete;
DefaultHeaders & operator=(DefaultHeaders const &) = delete; DefaultHeaders & operator=(DefaultHeaders const &) = delete;

View File

@@ -63,14 +63,49 @@ AsyncWebServerRequest::AsyncWebServerRequest(AsyncWebServer* s, AsyncClient* c)
, _itemBuffer(0) , _itemBuffer(0)
, _itemBufferIndex(0) , _itemBufferIndex(0)
, _itemIsFile(false) , _itemIsFile(false)
, _tempObject(NULL) , _tempObject(NULL) {
{ c->onError(
c->onError([](void *r, AsyncClient* c, int8_t error){ (void)c; AsyncWebServerRequest *req = (AsyncWebServerRequest*)r; req->_onError(error); }, this); [](void * r, AsyncClient * c, int8_t error) {
c->onAck([](void *r, AsyncClient* c, size_t len, uint32_t time){ (void)c; AsyncWebServerRequest *req = (AsyncWebServerRequest*)r; req->_onAck(len, time); }, this); (void)c;
c->onDisconnect([](void *r, AsyncClient* c){ AsyncWebServerRequest *req = (AsyncWebServerRequest*)r; req->_onDisconnect(); delete c; }, this); AsyncWebServerRequest * req = (AsyncWebServerRequest *)r;
c->onTimeout([](void *r, AsyncClient* c, uint32_t time){ (void)c; AsyncWebServerRequest *req = (AsyncWebServerRequest*)r; req->_onTimeout(time); }, this); req->_onError(error);
c->onData([](void *r, AsyncClient* c, void *buf, size_t len){ (void)c; AsyncWebServerRequest *req = (AsyncWebServerRequest*)r; req->_onData(buf, len); }, this); },
c->onPoll([](void *r, AsyncClient* c){ (void)c; AsyncWebServerRequest *req = ( AsyncWebServerRequest*)r; req->_onPoll(); }, this); this);
c->onAck(
[](void * r, AsyncClient * c, size_t len, uint32_t time) {
(void)c;
AsyncWebServerRequest * req = (AsyncWebServerRequest *)r;
req->_onAck(len, time);
},
this);
c->onDisconnect(
[](void * r, AsyncClient * c) {
AsyncWebServerRequest * req = (AsyncWebServerRequest *)r;
req->_onDisconnect();
delete c;
},
this);
c->onTimeout(
[](void * r, AsyncClient * c, uint32_t time) {
(void)c;
AsyncWebServerRequest * req = (AsyncWebServerRequest *)r;
req->_onTimeout(time);
},
this);
c->onData(
[](void * r, AsyncClient * c, void * buf, size_t len) {
(void)c;
AsyncWebServerRequest * req = (AsyncWebServerRequest *)r;
req->_onData(buf, len);
},
this);
c->onPoll(
[](void * r, AsyncClient * c) {
(void)c;
AsyncWebServerRequest * req = (AsyncWebServerRequest *)r;
req->_onPoll();
},
this);
} }
AsyncWebServerRequest::~AsyncWebServerRequest() { AsyncWebServerRequest::~AsyncWebServerRequest() {
@@ -96,13 +131,11 @@ AsyncWebServerRequest::~AsyncWebServerRequest(){
if (_itemBuffer) { if (_itemBuffer) {
free(_itemBuffer); free(_itemBuffer);
} }
} }
void AsyncWebServerRequest::_onData(void * buf, size_t len) { void AsyncWebServerRequest::_onData(void * buf, size_t len) {
size_t i = 0; size_t i = 0;
while (true) { while (true) {
if (_parseState < PARSE_REQ_BODY) { if (_parseState < PARSE_REQ_BODY) {
// Find new line in buf // Find new line in buf
char * str = (char *)buf; char * str = (char *)buf;
@@ -148,7 +181,8 @@ void AsyncWebServerRequest::_onData(void *buf, size_t len){
_isPlainPost = true; _isPlainPost = true;
} else if (_contentType == F("text/plain") && __is_param_char(((char *)buf)[0])) { } else if (_contentType == F("text/plain") && __is_param_char(((char *)buf)[0])) {
size_t i = 0; size_t i = 0;
while (i<len && __is_param_char(((char*)buf)[i++])); while (i < len && __is_param_char(((char *)buf)[i++]))
;
if (i < len && ((char *)buf)[i - 1] == '=') { if (i < len && ((char *)buf)[i - 1] == '=') {
_isPlainPost = true; _isPlainPost = true;
} }
@@ -156,7 +190,8 @@ void AsyncWebServerRequest::_onData(void *buf, size_t len){
} }
if (!_isPlainPost) { if (!_isPlainPost) {
//check if authenticated before calling the body //check if authenticated before calling the body
if(_handler) _handler->handleBody(this, (uint8_t*)buf, len, _parsedLength, _contentLength); if (_handler)
_handler->handleBody(this, (uint8_t *)buf, len, _parsedLength, _contentLength);
_parsedLength += len; _parsedLength += len;
} else if (needParse) { } else if (needParse) {
size_t i; size_t i;
@@ -171,8 +206,10 @@ void AsyncWebServerRequest::_onData(void *buf, size_t len){
if (_parsedLength == _contentLength) { if (_parsedLength == _contentLength) {
_parseState = PARSE_REQ_END; _parseState = PARSE_REQ_END;
//check if authenticated before calling handleRequest and request auth instead //check if authenticated before calling handleRequest and request auth instead
if(_handler) _handler->handleRequest(this); if (_handler)
else send(501); _handler->handleRequest(this);
else
send(501);
} }
} }
break; break;
@@ -180,16 +217,13 @@ 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 (std::any_of(std::begin(_interestingHeaders), std::end(_interestingHeaders), [](const String & str) { return str.equalsIgnoreCase(F("ANY")); }))
[](const String &str){ return str.equalsIgnoreCase(F("ANY")); }))
return; // nothing to do return; // nothing to do
for(auto iter = std::begin(_headers); iter != std::end(_headers); ) for (auto iter = std::begin(_headers); iter != std::end(_headers);) {
{
const auto name = iter->name(); const auto name = iter->name();
if (std::none_of(std::begin(_interestingHeaders), std::end(_interestingHeaders), if (std::none_of(std::begin(_interestingHeaders), std::end(_interestingHeaders), [&name](const String & str) { return str.equalsIgnoreCase(name); }))
[&name](const String &str){ return str.equalsIgnoreCase(name); }))
iter = _headers.erase(iter); iter = _headers.erase(iter);
else else
iter++; iter++;
@@ -260,9 +294,11 @@ void AsyncWebServerRequest::_addGetParams(const String& params){
size_t start = 0; size_t start = 0;
while (start < params.length()) { while (start < params.length()) {
int end = params.indexOf('&', start); int end = params.indexOf('&', start);
if (end < 0) end = params.length(); if (end < 0)
end = params.length();
int equal = params.indexOf('=', start); int equal = params.indexOf('=', start);
if (equal < 0 || equal > end) equal = end; if (equal < 0 || equal > end)
equal = end;
String name = params.substring(start, equal); String name = params.substring(start, equal);
String value = equal + 1 < end ? params.substring(equal + 1, end) : String(); String value = equal + 1 < end ? params.substring(equal + 1, end) : String();
_addParam(new AsyncWebParameter(urlDecode(name), urlDecode(value))); _addParam(new AsyncWebParameter(urlDecode(name), urlDecode(value)));
@@ -315,17 +351,19 @@ bool strContains(const String &src, const String &find, bool mindcase = true) {
const int slen = src.length(); const int slen = src.length();
const int flen = find.length(); const int flen = find.length();
if (slen < flen) return false; if (slen < flen)
return false;
while (pos <= (slen - flen)) { while (pos <= (slen - flen)) {
for (i = 0; i < flen; i++) { for (i = 0; i < flen; i++) {
if (mindcase) { if (mindcase) {
if (src[pos+i] != find[i]) i = flen + 1; // no match if (src[pos + i] != find[i])
} i = flen + 1; // no match
else if (tolower(src[pos+i]) != tolower(find[i])) { } else if (tolower(src[pos + i]) != tolower(find[i])) {
i = flen + 1; // no match i = flen + 1; // no match
} }
} }
if (i == flen) return true; if (i == flen)
return true;
pos++; pos++;
} }
return false; return false;
@@ -414,7 +452,14 @@ enum {
}; };
void AsyncWebServerRequest::_parseMultipartPostByte(uint8_t data, bool last) { void AsyncWebServerRequest::_parseMultipartPostByte(uint8_t data, bool last) {
#define itemWriteByte(b) do { _itemSize++; if(_itemIsFile) _handleUploadByte(b, last); else _itemValue+=(char)(b); } while(0) #define itemWriteByte(b) \
do { \
_itemSize++; \
if (_itemIsFile) \
_handleUploadByte(b, last); \
else \
_itemValue += (char)(b); \
} while (0)
if (!_parsedLength) { if (!_parsedLength) {
_multiParseState = EXPECT_BOUNDARY; _multiParseState = EXPECT_BOUNDARY;
@@ -500,21 +545,27 @@ void AsyncWebServerRequest::_parseMultipartPostByte(uint8_t data, bool last){
} else if (_multiParseState == EXPECT_FEED1) { } else if (_multiParseState == EXPECT_FEED1) {
if (data != '\n') { if (data != '\n') {
_multiParseState = WAIT_FOR_RETURN1; _multiParseState = WAIT_FOR_RETURN1;
itemWriteByte('\r'); _parseMultipartPostByte(data, last); itemWriteByte('\r');
_parseMultipartPostByte(data, last);
} else { } else {
_multiParseState = EXPECT_DASH1; _multiParseState = EXPECT_DASH1;
} }
} else if (_multiParseState == EXPECT_DASH1) { } else if (_multiParseState == EXPECT_DASH1) {
if (data != '-') { if (data != '-') {
_multiParseState = WAIT_FOR_RETURN1; _multiParseState = WAIT_FOR_RETURN1;
itemWriteByte('\r'); itemWriteByte('\n'); _parseMultipartPostByte(data, last); itemWriteByte('\r');
itemWriteByte('\n');
_parseMultipartPostByte(data, last);
} else { } else {
_multiParseState = EXPECT_DASH2; _multiParseState = EXPECT_DASH2;
} }
} else if (_multiParseState == EXPECT_DASH2) { } else if (_multiParseState == EXPECT_DASH2) {
if (data != '-') { if (data != '-') {
_multiParseState = WAIT_FOR_RETURN1; _multiParseState = WAIT_FOR_RETURN1;
itemWriteByte('\r'); itemWriteByte('\n'); itemWriteByte('-'); _parseMultipartPostByte(data, last); itemWriteByte('\r');
itemWriteByte('\n');
itemWriteByte('-');
_parseMultipartPostByte(data, last);
} else { } else {
_multiParseState = BOUNDARY_OR_DATA; _multiParseState = BOUNDARY_OR_DATA;
_boundaryPosition = 0; _boundaryPosition = 0;
@@ -522,7 +573,10 @@ void AsyncWebServerRequest::_parseMultipartPostByte(uint8_t data, bool last){
} else if (_multiParseState == BOUNDARY_OR_DATA) { } else if (_multiParseState == BOUNDARY_OR_DATA) {
if (_boundaryPosition < _boundary.length() && _boundary.c_str()[_boundaryPosition] != data) { if (_boundaryPosition < _boundary.length() && _boundary.c_str()[_boundaryPosition] != data) {
_multiParseState = WAIT_FOR_RETURN1; _multiParseState = WAIT_FOR_RETURN1;
itemWriteByte('\r'); itemWriteByte('\n'); itemWriteByte('-'); itemWriteByte('-'); itemWriteByte('\r');
itemWriteByte('\n');
itemWriteByte('-');
itemWriteByte('-');
uint8_t i; uint8_t i;
for (i = 0; i < _boundaryPosition; i++) for (i = 0; i < _boundaryPosition; i++)
itemWriteByte(_boundary.c_str()[i]); itemWriteByte(_boundary.c_str()[i]);
@@ -534,7 +588,8 @@ void AsyncWebServerRequest::_parseMultipartPostByte(uint8_t data, bool last){
} else { } else {
if (_itemSize) { if (_itemSize) {
//check if authenticated before calling the upload //check if authenticated before calling the upload
if(_handler) _handler->handleUpload(this, _itemFilename, _itemSize - _itemBufferIndex, _itemBuffer, _itemBufferIndex, true); if (_handler)
_handler->handleUpload(this, _itemFilename, _itemSize - _itemBufferIndex, _itemBuffer, _itemBufferIndex, true);
_itemBufferIndex = 0; _itemBufferIndex = 0;
_addParam(new AsyncWebParameter(_itemName, _itemFilename, true, true, _itemSize)); _addParam(new AsyncWebParameter(_itemName, _itemFilename, true, true, _itemSize));
} }
@@ -556,8 +611,13 @@ void AsyncWebServerRequest::_parseMultipartPostByte(uint8_t data, bool last){
_multiParseState = PARSING_FINISHED; _multiParseState = PARSING_FINISHED;
} else { } else {
_multiParseState = WAIT_FOR_RETURN1; _multiParseState = WAIT_FOR_RETURN1;
itemWriteByte('\r'); itemWriteByte('\n'); itemWriteByte('-'); itemWriteByte('-'); itemWriteByte('\r');
uint8_t i; for(i=0; i<_boundary.length(); i++) itemWriteByte(_boundary.c_str()[i]); itemWriteByte('\n');
itemWriteByte('-');
itemWriteByte('-');
uint8_t i;
for (i = 0; i < _boundary.length(); i++)
itemWriteByte(_boundary.c_str()[i]);
_parseMultipartPostByte(data, last); _parseMultipartPostByte(data, last);
} }
} else if (_multiParseState == EXPECT_FEED2) { } else if (_multiParseState == EXPECT_FEED2) {
@@ -566,9 +626,15 @@ void AsyncWebServerRequest::_parseMultipartPostByte(uint8_t data, bool last){
_itemIsFile = false; _itemIsFile = false;
} else { } else {
_multiParseState = WAIT_FOR_RETURN1; _multiParseState = WAIT_FOR_RETURN1;
itemWriteByte('\r'); itemWriteByte('\n'); itemWriteByte('-'); itemWriteByte('-'); itemWriteByte('\r');
uint8_t i; for(i=0; i<_boundary.length(); i++) itemWriteByte(_boundary.c_str()[i]); itemWriteByte('\n');
itemWriteByte('\r'); _parseMultipartPostByte(data, last); itemWriteByte('-');
itemWriteByte('-');
uint8_t i;
for (i = 0; i < _boundary.length(); i++)
itemWriteByte(_boundary.c_str()[i]);
itemWriteByte('\r');
_parseMultipartPostByte(data, last);
} }
} }
} }
@@ -600,10 +666,13 @@ void AsyncWebServerRequest::_parseLine(){
_parseState = PARSE_REQ_BODY; _parseState = PARSE_REQ_BODY;
} else { } else {
_parseState = PARSE_REQ_END; _parseState = PARSE_REQ_END;
if(_handler) _handler->handleRequest(this); if (_handler)
else send(501); _handler->handleRequest(this);
else
send(501);
} }
} else _parseReqHeader(); } else
_parseReqHeader();
} }
} }
@@ -625,8 +694,7 @@ bool AsyncWebServerRequest::hasHeader(const __FlashStringHelper * data) const {
} }
AsyncWebHeader * AsyncWebServerRequest::getHeader(const String & name) { AsyncWebHeader * AsyncWebServerRequest::getHeader(const String & name) {
auto iter = std::find_if(std::begin(_headers), std::end(_headers), auto iter = std::find_if(std::begin(_headers), std::end(_headers), [&name](const AsyncWebHeader & header) { return header.name().equalsIgnoreCase(name); });
[&name](const AsyncWebHeader &header){ return header.name().equalsIgnoreCase(name); });
if (iter == std::end(_headers)) if (iter == std::end(_headers))
return nullptr; return nullptr;
@@ -635,8 +703,7 @@ AsyncWebHeader* AsyncWebServerRequest::getHeader(const String& name) {
} }
const AsyncWebHeader * AsyncWebServerRequest::getHeader(const String & name) const { const AsyncWebHeader * AsyncWebServerRequest::getHeader(const String & name) const {
auto iter = std::find_if(std::begin(_headers), std::end(_headers), auto iter = std::find_if(std::begin(_headers), std::end(_headers), [&name](const AsyncWebHeader & header) { return header.name().equalsIgnoreCase(name); });
[&name](const AsyncWebHeader &header){ return header.name().equalsIgnoreCase(name); });
if (iter == std::end(_headers)) if (iter == std::end(_headers))
return nullptr; return nullptr;
@@ -720,8 +787,7 @@ 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 (std::none_of(std::begin(_interestingHeaders), std::end(_interestingHeaders), [&name](const String & str) { return str.equalsIgnoreCase(name); }))
[&name](const String &str){ return str.equalsIgnoreCase(name); }))
_interestingHeaders.push_back(name); _interestingHeaders.push_back(name);
} }
@@ -736,8 +802,7 @@ void AsyncWebServerRequest::send(AsyncWebServerResponse *response){
delete response; delete response;
_response = NULL; _response = NULL;
send(500); send(500);
} } else {
else {
_client->setRxTimeout(0); _client->setRxTimeout(0);
_response->_respond(this); _response->_respond(this);
} }
@@ -747,13 +812,15 @@ AsyncWebServerResponse * AsyncWebServerRequest::beginResponse(int code, const St
return new AsyncBasicResponse(code, contentType, content); return new AsyncBasicResponse(code, contentType, content);
} }
AsyncWebServerResponse * AsyncWebServerRequest::beginResponse(FS &fs, const String& path, const String& contentType, bool download, AwsTemplateProcessor callback){ AsyncWebServerResponse *
AsyncWebServerRequest::beginResponse(FS & fs, const String & path, const String & contentType, bool download, AwsTemplateProcessor callback) {
if (fs.exists(path) || (!download && fs.exists(path + F(".gz")))) if (fs.exists(path) || (!download && fs.exists(path + F(".gz"))))
return new AsyncFileResponse(fs, path, contentType, download, callback); return new AsyncFileResponse(fs, path, contentType, download, callback);
return NULL; return NULL;
} }
AsyncWebServerResponse * AsyncWebServerRequest::beginResponse(File content, const String& path, const String& contentType, bool download, AwsTemplateProcessor callback){ AsyncWebServerResponse *
AsyncWebServerRequest::beginResponse(File content, const String & path, const String & contentType, bool download, AwsTemplateProcessor callback) {
if (content == true) if (content == true)
return new AsyncFileResponse(content, path, contentType, download, callback); return new AsyncFileResponse(content, path, contentType, download, callback);
return NULL; return NULL;
@@ -763,11 +830,13 @@ AsyncWebServerResponse * AsyncWebServerRequest::beginResponse(Stream &stream, co
return new AsyncStreamResponse(stream, contentType, len, callback); return new AsyncStreamResponse(stream, contentType, len, callback);
} }
AsyncWebServerResponse * AsyncWebServerRequest::beginResponse(const String& contentType, size_t len, AwsResponseFiller callback, AwsTemplateProcessor templateCallback){ AsyncWebServerResponse *
AsyncWebServerRequest::beginResponse(const String & contentType, size_t len, AwsResponseFiller callback, AwsTemplateProcessor templateCallback) {
return new AsyncCallbackResponse(contentType, len, callback, templateCallback); return new AsyncCallbackResponse(contentType, len, callback, templateCallback);
} }
AsyncWebServerResponse * AsyncWebServerRequest::beginChunkedResponse(const String& contentType, AwsResponseFiller callback, AwsTemplateProcessor templateCallback){ AsyncWebServerResponse *
AsyncWebServerRequest::beginChunkedResponse(const String & contentType, AwsResponseFiller callback, AwsTemplateProcessor templateCallback) {
if (_version) if (_version)
return new AsyncChunkedResponse(contentType, callback, templateCallback); return new AsyncChunkedResponse(contentType, callback, templateCallback);
return new AsyncCallbackResponse(contentType, 0, callback, templateCallback); return new AsyncCallbackResponse(contentType, 0, callback, templateCallback);
@@ -777,7 +846,8 @@ AsyncResponseStream * AsyncWebServerRequest::beginResponseStream(const String& c
return new AsyncResponseStream(contentType, bufferSize); return new AsyncResponseStream(contentType, bufferSize);
} }
AsyncWebServerResponse * AsyncWebServerRequest::beginResponse_P(int code, const String& contentType, const uint8_t * content, size_t len, AwsTemplateProcessor callback){ AsyncWebServerResponse *
AsyncWebServerRequest::beginResponse_P(int code, const String & contentType, const uint8_t * content, size_t len, AwsTemplateProcessor callback) {
return new AsyncProgmemResponse(code, contentType, content, len, callback); return new AsyncProgmemResponse(code, contentType, content, len, callback);
} }
@@ -785,6 +855,12 @@ AsyncWebServerResponse * AsyncWebServerRequest::beginResponse_P(int code, const
return beginResponse_P(code, contentType, (const uint8_t *)content, strlen_P(content), callback); return beginResponse_P(code, contentType, (const uint8_t *)content, strlen_P(content), callback);
} }
// added by proddy
AsyncWebServerResponse *
AsyncWebServerRequest::beginResponse(const String & contentType, const uint8_t * content, size_t len) {
return new AsyncResponse(contentType, content, len);
}
void AsyncWebServerRequest::send(int code, const String & contentType, const String & content) { void AsyncWebServerRequest::send(int code, const String & contentType, const String & content) {
send(beginResponse(code, contentType, content)); send(beginResponse(code, contentType, content));
} }
@@ -792,13 +868,15 @@ void AsyncWebServerRequest::send(int code, const String& contentType, const Stri
void AsyncWebServerRequest::send(FS & fs, const String & path, const String & contentType, bool download, AwsTemplateProcessor callback) { void AsyncWebServerRequest::send(FS & fs, const String & path, const String & contentType, bool download, AwsTemplateProcessor callback) {
if (fs.exists(path) || (!download && fs.exists(path + F(".gz")))) { if (fs.exists(path) || (!download && fs.exists(path + F(".gz")))) {
send(beginResponse(fs, path, contentType, download, callback)); send(beginResponse(fs, path, contentType, download, callback));
} else send(404); } else
send(404);
} }
void AsyncWebServerRequest::send(File content, const String & path, const String & contentType, bool download, AwsTemplateProcessor callback) { void AsyncWebServerRequest::send(File content, const String & path, const String & contentType, bool download, AwsTemplateProcessor callback) {
if (content == true) { if (content == true) {
send(beginResponse(content, path, contentType, download, callback)); send(beginResponse(content, path, contentType, download, callback));
} else send(404); } else
send(404);
} }
void AsyncWebServerRequest::send(Stream & stream, const String & contentType, size_t len, AwsTemplateProcessor callback) { void AsyncWebServerRequest::send(Stream & stream, const String & contentType, size_t len, AwsTemplateProcessor callback) {
@@ -962,32 +1040,49 @@ String AsyncWebServerRequest::urlDecode(const String& text) const {
const __FlashStringHelper * AsyncWebServerRequest::methodToString() const { const __FlashStringHelper * AsyncWebServerRequest::methodToString() const {
if(_method == HTTP_ANY) return F("ANY"); if (_method == HTTP_ANY)
else if(_method & HTTP_GET) return F("GET"); return F("ANY");
else if(_method & HTTP_POST) return F("POST"); else if (_method & HTTP_GET)
else if(_method & HTTP_DELETE) return F("DELETE"); return F("GET");
else if(_method & HTTP_PUT) return F("PUT"); else if (_method & HTTP_POST)
else if(_method & HTTP_PATCH) return F("PATCH"); return F("POST");
else if(_method & HTTP_HEAD) return F("HEAD"); else if (_method & HTTP_DELETE)
else if(_method & HTTP_OPTIONS) return F("OPTIONS"); return F("DELETE");
else if (_method & HTTP_PUT)
return F("PUT");
else if (_method & HTTP_PATCH)
return F("PATCH");
else if (_method & HTTP_HEAD)
return F("HEAD");
else if (_method & HTTP_OPTIONS)
return F("OPTIONS");
return F("UNKNOWN"); return F("UNKNOWN");
} }
const __FlashStringHelper * AsyncWebServerRequest::requestedConnTypeToString() const { const __FlashStringHelper * AsyncWebServerRequest::requestedConnTypeToString() const {
switch (_reqconntype) { switch (_reqconntype) {
case RCT_NOT_USED: return F("RCT_NOT_USED"); case RCT_NOT_USED:
case RCT_DEFAULT: return F("RCT_DEFAULT"); return F("RCT_NOT_USED");
case RCT_HTTP: return F("RCT_HTTP"); case RCT_DEFAULT:
case RCT_WS: return F("RCT_WS"); return F("RCT_DEFAULT");
case RCT_EVENT: return F("RCT_EVENT"); case RCT_HTTP:
default: return F("ERROR"); return F("RCT_HTTP");
case RCT_WS:
return F("RCT_WS");
case RCT_EVENT:
return F("RCT_EVENT");
default:
return F("ERROR");
} }
} }
bool AsyncWebServerRequest::isExpectedRequestedConnType(RequestedConnectionType erct1, RequestedConnectionType erct2, RequestedConnectionType erct3) { bool AsyncWebServerRequest::isExpectedRequestedConnType(RequestedConnectionType erct1, RequestedConnectionType erct2, RequestedConnectionType erct3) {
bool res = false; bool res = false;
if ((erct1 != RCT_NOT_USED) && (erct1 == _reqconntype)) res = true; if ((erct1 != RCT_NOT_USED) && (erct1 == _reqconntype))
if ((erct2 != RCT_NOT_USED) && (erct2 == _reqconntype)) res = true; res = true;
if ((erct3 != RCT_NOT_USED) && (erct3 == _reqconntype)) res = true; if ((erct2 != RCT_NOT_USED) && (erct2 == _reqconntype))
res = true;
if ((erct3 != RCT_NOT_USED) && (erct3 == _reqconntype))
res = true;
return res; return res;
} }

View File

@@ -34,11 +34,14 @@
class AsyncBasicResponse : public AsyncWebServerResponse { class AsyncBasicResponse : public AsyncWebServerResponse {
private: private:
String _content; String _content;
public: public:
AsyncBasicResponse(int code, const String & contentType = String(), const String & content = String()); AsyncBasicResponse(int code, const String & contentType = String(), const String & content = String());
void _respond(AsyncWebServerRequest * request); void _respond(AsyncWebServerRequest * request);
size_t _ack(AsyncWebServerRequest * request, size_t len, uint32_t time); size_t _ack(AsyncWebServerRequest * request, size_t len, uint32_t time);
bool _sourceValid() const { return true; } bool _sourceValid() const {
return true;
}
}; };
class AsyncAbstractResponse : public AsyncWebServerResponse { class AsyncAbstractResponse : public AsyncWebServerResponse {
@@ -51,14 +54,20 @@ class AsyncAbstractResponse: public AsyncWebServerResponse {
std::vector<uint8_t> _cache; std::vector<uint8_t> _cache;
size_t _readDataFromCacheOrContent(uint8_t * data, const size_t len); size_t _readDataFromCacheOrContent(uint8_t * data, const size_t len);
size_t _fillBufferAndProcessTemplates(uint8_t * buf, size_t maxLen); size_t _fillBufferAndProcessTemplates(uint8_t * buf, size_t maxLen);
protected: protected:
AwsTemplateProcessor _callback; AwsTemplateProcessor _callback;
public: public:
AsyncAbstractResponse(AwsTemplateProcessor callback = nullptr); AsyncAbstractResponse(AwsTemplateProcessor callback = nullptr);
void _respond(AsyncWebServerRequest * request); void _respond(AsyncWebServerRequest * request);
size_t _ack(AsyncWebServerRequest * request, size_t len, uint32_t time); size_t _ack(AsyncWebServerRequest * request, size_t len, uint32_t time);
bool _sourceValid() const { return false; } bool _sourceValid() const {
virtual size_t _fillBuffer(uint8_t *buf __attribute__((unused)), size_t maxLen __attribute__((unused))) { return 0; } return false;
}
virtual size_t _fillBuffer(uint8_t * buf __attribute__((unused)), size_t maxLen __attribute__((unused))) {
return 0;
}
}; };
#ifndef TEMPLATE_PLACEHOLDER #ifndef TEMPLATE_PLACEHOLDER
@@ -69,24 +78,31 @@ class AsyncAbstractResponse: public AsyncWebServerResponse {
class AsyncFileResponse : public AsyncAbstractResponse { class AsyncFileResponse : public AsyncAbstractResponse {
using File = fs::File; using File = fs::File;
using FS = fs::FS; using FS = fs::FS;
private: private:
File _content; File _content;
String _path; String _path;
void _setContentType(const String & path); void _setContentType(const String & path);
public: public:
AsyncFileResponse(FS & fs, 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(File content, const String & path, const String & contentType = String(), bool download = false, AwsTemplateProcessor callback = nullptr);
~AsyncFileResponse(); ~AsyncFileResponse();
bool _sourceValid() const { return !!(_content); } bool _sourceValid() const {
return !!(_content);
}
virtual size_t _fillBuffer(uint8_t * buf, size_t maxLen) override; virtual size_t _fillBuffer(uint8_t * buf, size_t maxLen) override;
}; };
class AsyncStreamResponse : public AsyncAbstractResponse { class AsyncStreamResponse : public AsyncAbstractResponse {
private: private:
Stream * _content; Stream * _content;
public: public:
AsyncStreamResponse(Stream & stream, const String & contentType, size_t len, AwsTemplateProcessor callback = nullptr); AsyncStreamResponse(Stream & stream, const String & contentType, size_t len, AwsTemplateProcessor callback = nullptr);
bool _sourceValid() const { return !!(_content); } bool _sourceValid() const {
return !!(_content);
}
virtual size_t _fillBuffer(uint8_t * buf, size_t maxLen) override; virtual size_t _fillBuffer(uint8_t * buf, size_t maxLen) override;
}; };
@@ -94,9 +110,12 @@ class AsyncCallbackResponse: public AsyncAbstractResponse {
private: private:
AwsResponseFiller _content; AwsResponseFiller _content;
size_t _filledLength; size_t _filledLength;
public: public:
AsyncCallbackResponse(const String & contentType, size_t len, AwsResponseFiller callback, AwsTemplateProcessor templateCallback = nullptr); AsyncCallbackResponse(const String & contentType, size_t len, AwsResponseFiller callback, AwsTemplateProcessor templateCallback = nullptr);
bool _sourceValid() const { return !!(_content); } bool _sourceValid() const {
return !!(_content);
}
virtual size_t _fillBuffer(uint8_t * buf, size_t maxLen) override; virtual size_t _fillBuffer(uint8_t * buf, size_t maxLen) override;
}; };
@@ -104,9 +123,12 @@ class AsyncChunkedResponse: public AsyncAbstractResponse {
private: private:
AwsResponseFiller _content; AwsResponseFiller _content;
size_t _filledLength; size_t _filledLength;
public: public:
AsyncChunkedResponse(const String & contentType, AwsResponseFiller callback, AwsTemplateProcessor templateCallback = nullptr); AsyncChunkedResponse(const String & contentType, AwsResponseFiller callback, AwsTemplateProcessor templateCallback = nullptr);
bool _sourceValid() const { return !!(_content); } bool _sourceValid() const {
return !!(_content);
}
virtual size_t _fillBuffer(uint8_t * buf, size_t maxLen) override; virtual size_t _fillBuffer(uint8_t * buf, size_t maxLen) override;
}; };
@@ -114,9 +136,26 @@ class AsyncProgmemResponse: public AsyncAbstractResponse {
private: private:
const uint8_t * _content; const uint8_t * _content;
size_t _readLength; size_t _readLength;
public: public:
AsyncProgmemResponse(int code, const String & contentType, const uint8_t * content, size_t len, AwsTemplateProcessor callback = nullptr); AsyncProgmemResponse(int code, const String & contentType, const uint8_t * content, size_t len, AwsTemplateProcessor callback = nullptr);
bool _sourceValid() const { return true; } 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; virtual size_t _fillBuffer(uint8_t * buf, size_t maxLen) override;
}; };
@@ -125,10 +164,13 @@ class cbuf;
class AsyncResponseStream : public AsyncAbstractResponse, public Print { class AsyncResponseStream : public AsyncAbstractResponse, public Print {
private: private:
std::unique_ptr<cbuf> _content; std::unique_ptr<cbuf> _content;
public: public:
AsyncResponseStream(const String & contentType, size_t bufferSize); AsyncResponseStream(const String & contentType, size_t bufferSize);
~AsyncResponseStream(); ~AsyncResponseStream();
bool _sourceValid() const { return (_state < RESPONSE_END); } bool _sourceValid() const {
return (_state < RESPONSE_END);
}
virtual size_t _fillBuffer(uint8_t * buf, size_t maxLen) override; virtual size_t _fillBuffer(uint8_t * buf, size_t maxLen) override;
size_t write(const uint8_t * data, size_t len); size_t write(const uint8_t * data, size_t len);
size_t write(uint8_t data); size_t write(uint8_t data);

View File

@@ -23,8 +23,7 @@
#include "cbuf.h" #include "cbuf.h"
// Since ESP8266 does not link memchr by default, here's its implementation. // Since ESP8266 does not link memchr by default, here's its implementation.
void* memchr(void* ptr, int ch, size_t count) void * memchr(void * ptr, int ch, size_t count) {
{
unsigned char * p = static_cast<unsigned char *>(ptr); unsigned char * p = static_cast<unsigned char *>(ptr);
while (count--) while (count--)
if (*p++ == static_cast<unsigned char>(ch)) if (*p++ == static_cast<unsigned char>(ch))
@@ -42,47 +41,88 @@ const char* AsyncWebServerResponse::_responseCodeToString(int code) {
const __FlashStringHelper * AsyncWebServerResponse::responseCodeToString(int code) { const __FlashStringHelper * AsyncWebServerResponse::responseCodeToString(int code) {
switch (code) { switch (code) {
case 100: return F("Continue"); case 100:
case 101: return F("Switching Protocols"); return F("Continue");
case 200: return F("OK"); case 101:
case 201: return F("Created"); return F("Switching Protocols");
case 202: return F("Accepted"); case 200:
case 203: return F("Non-Authoritative Information"); return F("OK");
case 204: return F("No Content"); case 201:
case 205: return F("Reset Content"); return F("Created");
case 206: return F("Partial Content"); case 202:
case 300: return F("Multiple Choices"); return F("Accepted");
case 301: return F("Moved Permanently"); case 203:
case 302: return F("Found"); return F("Non-Authoritative Information");
case 303: return F("See Other"); case 204:
case 304: return F("Not Modified"); return F("No Content");
case 305: return F("Use Proxy"); case 205:
case 307: return F("Temporary Redirect"); return F("Reset Content");
case 400: return F("Bad Request"); case 206:
case 401: return F("Unauthorized"); return F("Partial Content");
case 402: return F("Payment Required"); case 300:
case 403: return F("Forbidden"); return F("Multiple Choices");
case 404: return F("Not Found"); case 301:
case 405: return F("Method Not Allowed"); return F("Moved Permanently");
case 406: return F("Not Acceptable"); case 302:
case 407: return F("Proxy Authentication Required"); return F("Found");
case 408: return F("Request Time-out"); case 303:
case 409: return F("Conflict"); return F("See Other");
case 410: return F("Gone"); case 304:
case 411: return F("Length Required"); return F("Not Modified");
case 412: return F("Precondition Failed"); case 305:
case 413: return F("Request Entity Too Large"); return F("Use Proxy");
case 414: return F("Request-URI Too Large"); case 307:
case 415: return F("Unsupported Media Type"); return F("Temporary Redirect");
case 416: return F("Requested range not satisfiable"); case 400:
case 417: return F("Expectation Failed"); return F("Bad Request");
case 500: return F("Internal Server Error"); case 401:
case 501: return F("Not Implemented"); return F("Unauthorized");
case 502: return F("Bad Gateway"); case 402:
case 503: return F("Service Unavailable"); return F("Payment Required");
case 504: return F("Gateway Time-out"); case 403:
case 505: return F("HTTP Version not supported"); return F("Forbidden");
default: return F(""); case 404:
return F("Not Found");
case 405:
return F("Method Not Allowed");
case 406:
return F("Not Acceptable");
case 407:
return F("Proxy Authentication Required");
case 408:
return F("Request Time-out");
case 409:
return F("Conflict");
case 410:
return F("Gone");
case 411:
return F("Length Required");
case 412:
return F("Precondition Failed");
case 413:
return F("Request Entity Too Large");
case 414:
return F("Request-URI Too Large");
case 415:
return F("Unsupported Media Type");
case 416:
return F("Requested range not satisfiable");
case 417:
return F("Expectation Failed");
case 500:
return F("Internal Server Error");
case 501:
return F("Not Implemented");
case 502:
return F("Bad Gateway");
case 503:
return F("Service Unavailable");
case 504:
return F("Gateway Time-out");
case 505:
return F("HTTP Version not supported");
default:
return F("");
} }
} }
@@ -96,8 +136,7 @@ AsyncWebServerResponse::AsyncWebServerResponse()
, _sentLength(0) , _sentLength(0)
, _ackedLength(0) , _ackedLength(0)
, _writtenLength(0) , _writtenLength(0)
, _state(RESPONSE_SETUP) , _state(RESPONSE_SETUP) {
{
for (const auto & header : DefaultHeaders::Instance()) { for (const auto & header : DefaultHeaders::Instance()) {
_headers.emplace_back(header); _headers.emplace_back(header);
} }
@@ -157,12 +196,28 @@ String AsyncWebServerResponse::_assembleHead(uint8_t version){
return out; return out;
} }
bool AsyncWebServerResponse::_started() const { return _state > RESPONSE_SETUP; } bool AsyncWebServerResponse::_started() const {
bool AsyncWebServerResponse::_finished() const { return _state > RESPONSE_WAIT_ACK; } return _state > RESPONSE_SETUP;
bool AsyncWebServerResponse::_failed() const { return _state == RESPONSE_FAILED; } }
bool AsyncWebServerResponse::_sourceValid() const { return false; } bool AsyncWebServerResponse::_finished() const {
void AsyncWebServerResponse::_respond(AsyncWebServerRequest *request){ _state = RESPONSE_END; request->client()->close(); } return _state > RESPONSE_WAIT_ACK;
size_t AsyncWebServerResponse::_ack(AsyncWebServerRequest *request, size_t len, uint32_t time){ (void)request; (void)len; (void)time; return 0; } }
bool AsyncWebServerResponse::_failed() const {
return _state == RESPONSE_FAILED;
}
bool AsyncWebServerResponse::_sourceValid() const {
return false;
}
void AsyncWebServerResponse::_respond(AsyncWebServerRequest * request) {
_state = RESPONSE_END;
request->client()->close();
}
size_t AsyncWebServerResponse::_ack(AsyncWebServerRequest * request, size_t len, uint32_t time) {
(void)request;
(void)len;
(void)time;
return 0;
}
/* /*
* String/Code Response * String/Code Response
@@ -245,8 +300,8 @@ size_t AsyncBasicResponse::_ack(AsyncWebServerRequest *request, size_t len, uint
* Abstract Response * Abstract Response
* */ * */
AsyncAbstractResponse::AsyncAbstractResponse(AwsTemplateProcessor callback): _callback(callback) AsyncAbstractResponse::AsyncAbstractResponse(AwsTemplateProcessor callback)
{ : _callback(callback) {
// In case of template processing, we're unable to determine real response size // In case of template processing, we're unable to determine real response size
if (callback) { if (callback) {
_contentLength = 0; _contentLength = 0;
@@ -319,7 +374,8 @@ size_t AsyncAbstractResponse::_ack(AsyncWebServerRequest *request, size_t len, u
return 0; return 0;
} }
outLen = sprintf_P((char *)buf + headLen, PSTR("%x"), readLen) + headLen; outLen = sprintf_P((char *)buf + headLen, PSTR("%x"), readLen) + headLen;
while(outLen < headLen + 4) buf[outLen++] = ' '; while (outLen < headLen + 4)
buf[outLen++] = ' ';
buf[outLen++] = '\r'; buf[outLen++] = '\r';
buf[outLen++] = '\n'; buf[outLen++] = '\n';
outLen += readLen; outLen += readLen;
@@ -365,8 +421,7 @@ size_t AsyncAbstractResponse::_ack(AsyncWebServerRequest *request, size_t len, u
return 0; return 0;
} }
size_t AsyncAbstractResponse::_readDataFromCacheOrContent(uint8_t* data, const size_t len) size_t AsyncAbstractResponse::_readDataFromCacheOrContent(uint8_t * data, const size_t len) {
{
// If we have something in cache, copy it to buffer // If we have something in cache, copy it to buffer
const size_t readFromCache = std::min(len, _cache.size()); const size_t readFromCache = std::min(len, _cache.size());
if (readFromCache) { if (readFromCache) {
@@ -379,8 +434,7 @@ size_t AsyncAbstractResponse::_readDataFromCacheOrContent(uint8_t* data, const s
return readFromCache + readFromContent; return readFromCache + readFromContent;
} }
size_t AsyncAbstractResponse::_fillBufferAndProcessTemplates(uint8_t* data, size_t len) size_t AsyncAbstractResponse::_fillBufferAndProcessTemplates(uint8_t * data, size_t len) {
{
if (!_callback) if (!_callback)
return _fillBuffer(data, len); return _fillBuffer(data, len);
@@ -389,8 +443,10 @@ size_t AsyncAbstractResponse::_fillBufferAndProcessTemplates(uint8_t* data, size
// Now we've read 'len' bytes, either from cache or from file // Now we've read 'len' bytes, either from cache or from file
// Search for template placeholders // Search for template placeholders
uint8_t * pTemplateStart = data; uint8_t * pTemplateStart = data;
while((pTemplateStart < &data[len]) && (pTemplateStart = (uint8_t*)memchr(pTemplateStart, TEMPLATE_PLACEHOLDER, &data[len - 1] - pTemplateStart + 1))) { // data[0] ... data[len - 1] while ((pTemplateStart < &data[len])
uint8_t* pTemplateEnd = (pTemplateStart < &data[len - 1]) ? (uint8_t*)memchr(pTemplateStart + 1, TEMPLATE_PLACEHOLDER, &data[len - 1] - pTemplateStart) : nullptr; && (pTemplateStart = (uint8_t *)memchr(pTemplateStart, TEMPLATE_PLACEHOLDER, &data[len - 1] - pTemplateStart + 1))) { // data[0] ... data[len - 1]
uint8_t * pTemplateEnd =
(pTemplateStart < &data[len - 1]) ? (uint8_t *)memchr(pTemplateStart + 1, TEMPLATE_PLACEHOLDER, &data[len - 1] - pTemplateStart) : nullptr;
// temporary buffer to hold parameter name // temporary buffer to hold parameter name
uint8_t buf[TEMPLATE_PARAM_NAME_LENGTH + 1]; uint8_t buf[TEMPLATE_PARAM_NAME_LENGTH + 1];
String paramName; String paramName;
@@ -410,7 +466,8 @@ size_t AsyncAbstractResponse::_fillBufferAndProcessTemplates(uint8_t* data, size
} }
} else if (&data[len - 1] - pTemplateStart + 1 < TEMPLATE_PARAM_NAME_LENGTH + 2) { // closing placeholder not found, check if it's in the remaining file data } else if (&data[len - 1] - pTemplateStart + 1 < TEMPLATE_PARAM_NAME_LENGTH + 2) { // closing placeholder not found, check if it's in the remaining file data
memcpy(buf, pTemplateStart + 1, &data[len - 1] - pTemplateStart); memcpy(buf, pTemplateStart + 1, &data[len - 1] - pTemplateStart);
const size_t readFromCacheOrContent = _readDataFromCacheOrContent(buf + (&data[len - 1] - pTemplateStart), TEMPLATE_PARAM_NAME_LENGTH + 2 - (&data[len - 1] - pTemplateStart + 1)); const size_t readFromCacheOrContent =
_readDataFromCacheOrContent(buf + (&data[len - 1] - pTemplateStart), TEMPLATE_PARAM_NAME_LENGTH + 2 - (&data[len - 1] - pTemplateStart + 1));
if (readFromCacheOrContent) { if (readFromCacheOrContent) {
pTemplateEnd = (uint8_t *)memchr(buf + (&data[len - 1] - pTemplateStart), TEMPLATE_PLACEHOLDER, readFromCacheOrContent); pTemplateEnd = (uint8_t *)memchr(buf + (&data[len - 1] - pTemplateStart), TEMPLATE_PLACEHOLDER, readFromCacheOrContent);
if (pTemplateEnd) { if (pTemplateEnd) {
@@ -420,18 +477,15 @@ size_t AsyncAbstractResponse::_fillBufferAndProcessTemplates(uint8_t* data, size
// Copy remaining read-ahead data into cache // Copy remaining read-ahead data into cache
_cache.insert(_cache.begin(), pTemplateEnd + 1, buf + (&data[len - 1] - pTemplateStart) + readFromCacheOrContent); _cache.insert(_cache.begin(), pTemplateEnd + 1, buf + (&data[len - 1] - pTemplateStart) + readFromCacheOrContent);
pTemplateEnd = &data[len - 1]; pTemplateEnd = &data[len - 1];
} } else // closing placeholder not found in file data, store found percent symbol as is and advance to the next position
else // closing placeholder not found in file data, store found percent symbol as is and advance to the next position
{ {
// but first, store read file data in cache // but first, store read file data in cache
_cache.insert(_cache.begin(), buf + (&data[len - 1] - pTemplateStart), buf + (&data[len - 1] - pTemplateStart) + readFromCacheOrContent); _cache.insert(_cache.begin(), buf + (&data[len - 1] - pTemplateStart), buf + (&data[len - 1] - pTemplateStart) + readFromCacheOrContent);
++pTemplateStart; ++pTemplateStart;
} }
} } else // closing placeholder not found in content data, store found percent symbol as is and advance to the next position
else // closing placeholder not found in content data, store found percent symbol as is and advance to the next position
++pTemplateStart; ++pTemplateStart;
} } else // closing placeholder not found in content data, store found percent symbol as is and advance to the next position
else // closing placeholder not found in content data, store found percent symbol as is and advance to the next position
++pTemplateStart; ++pTemplateStart;
if (paramName.length()) { if (paramName.length()) {
// call callback and replace with result. // call callback and replace with result.
@@ -488,29 +542,49 @@ void AsyncFileResponse::_setContentType(const String& path){
extern const __FlashStringHelper * getContentType(const String & path); extern const __FlashStringHelper * getContentType(const String & path);
_contentType = getContentType(path); _contentType = getContentType(path);
#else #else
if (path.endsWith(F(".html"))) _contentType = F("text/html"); if (path.endsWith(F(".html")))
else if (path.endsWith(F(".htm"))) _contentType = F("text/html"); _contentType = F("text/html");
else if (path.endsWith(F(".css"))) _contentType = F("text/css"); else if (path.endsWith(F(".htm")))
else if (path.endsWith(F(".json"))) _contentType = F("application/json"); _contentType = F("text/html");
else if (path.endsWith(F(".js"))) _contentType = F("application/javascript"); else if (path.endsWith(F(".css")))
else if (path.endsWith(F(".png"))) _contentType = F("image/png"); _contentType = F("text/css");
else if (path.endsWith(F(".gif"))) _contentType = F("image/gif"); else if (path.endsWith(F(".json")))
else if (path.endsWith(F(".jpg"))) _contentType = F("image/jpeg"); _contentType = F("application/json");
else if (path.endsWith(F(".ico"))) _contentType = F("image/x-icon"); else if (path.endsWith(F(".js")))
else if (path.endsWith(F(".svg"))) _contentType = F("image/svg+xml"); _contentType = F("application/javascript");
else if (path.endsWith(F(".eot"))) _contentType = F("font/eot"); else if (path.endsWith(F(".png")))
else if (path.endsWith(F(".woff"))) _contentType = F("font/woff"); _contentType = F("image/png");
else if (path.endsWith(F(".woff2"))) _contentType = F("font/woff2"); else if (path.endsWith(F(".gif")))
else if (path.endsWith(F(".ttf"))) _contentType = F("font/ttf"); _contentType = F("image/gif");
else if (path.endsWith(F(".xml"))) _contentType = F("text/xml"); else if (path.endsWith(F(".jpg")))
else if (path.endsWith(F(".pdf"))) _contentType = F("application/pdf"); _contentType = F("image/jpeg");
else if (path.endsWith(F(".zip"))) _contentType = F("application/zip"); else if (path.endsWith(F(".ico")))
else if(path.endsWith(F(".gz"))) _contentType = F("application/x-gzip"); _contentType = F("image/x-icon");
else _contentType = F("text/plain"); else if (path.endsWith(F(".svg")))
_contentType = F("image/svg+xml");
else if (path.endsWith(F(".eot")))
_contentType = F("font/eot");
else if (path.endsWith(F(".woff")))
_contentType = F("font/woff");
else if (path.endsWith(F(".woff2")))
_contentType = F("font/woff2");
else if (path.endsWith(F(".ttf")))
_contentType = F("font/ttf");
else if (path.endsWith(F(".xml")))
_contentType = F("text/xml");
else if (path.endsWith(F(".pdf")))
_contentType = F("application/pdf");
else if (path.endsWith(F(".zip")))
_contentType = F("application/zip");
else if (path.endsWith(F(".gz")))
_contentType = F("application/x-gzip");
else
_contentType = F("text/plain");
#endif #endif
} }
AsyncFileResponse::AsyncFileResponse(FS &fs, const String& path, const String& contentType, bool download, AwsTemplateProcessor callback): AsyncAbstractResponse(callback){ AsyncFileResponse::AsyncFileResponse(FS & fs, const String & path, const String & contentType, bool download, AwsTemplateProcessor callback)
: AsyncAbstractResponse(callback) {
_code = 200; _code = 200;
_path = path; _path = path;
@@ -544,7 +618,8 @@ AsyncFileResponse::AsyncFileResponse(FS &fs, const String& path, const String& c
addHeader(F("Content-Disposition"), buf); addHeader(F("Content-Disposition"), buf);
} }
AsyncFileResponse::AsyncFileResponse(File content, const String& path, const String& contentType, bool download, AwsTemplateProcessor callback): AsyncAbstractResponse(callback){ AsyncFileResponse::AsyncFileResponse(File content, const String & path, const String & contentType, bool download, AwsTemplateProcessor callback)
: AsyncAbstractResponse(callback) {
_code = 200; _code = 200;
_path = path; _path = path;
@@ -583,7 +658,8 @@ size_t AsyncFileResponse::_fillBuffer(uint8_t *data, size_t len){
* Stream Response * Stream Response
* */ * */
AsyncStreamResponse::AsyncStreamResponse(Stream &stream, const String& contentType, size_t len, AwsTemplateProcessor callback): AsyncAbstractResponse(callback) { AsyncStreamResponse::AsyncStreamResponse(Stream & stream, const String & contentType, size_t len, AwsTemplateProcessor callback)
: AsyncAbstractResponse(callback) {
_code = 200; _code = 200;
_content = &stream; _content = &stream;
_contentLength = len; _contentLength = len;
@@ -603,7 +679,8 @@ size_t AsyncStreamResponse::_fillBuffer(uint8_t *data, size_t len){
* Callback Response * Callback Response
* */ * */
AsyncCallbackResponse::AsyncCallbackResponse(const String& contentType, size_t len, AwsResponseFiller callback, AwsTemplateProcessor templateCallback): AsyncAbstractResponse(templateCallback) { AsyncCallbackResponse::AsyncCallbackResponse(const String & contentType, size_t len, AwsResponseFiller callback, AwsTemplateProcessor templateCallback)
: AsyncAbstractResponse(templateCallback) {
_code = 200; _code = 200;
_content = callback; _content = callback;
_contentLength = len; _contentLength = len;
@@ -625,7 +702,8 @@ size_t AsyncCallbackResponse::_fillBuffer(uint8_t *data, size_t len){
* Chunked Response * Chunked Response
* */ * */
AsyncChunkedResponse::AsyncChunkedResponse(const String& contentType, AwsResponseFiller callback, AwsTemplateProcessor processorCallback): AsyncAbstractResponse(processorCallback) { AsyncChunkedResponse::AsyncChunkedResponse(const String & contentType, AwsResponseFiller callback, AwsTemplateProcessor processorCallback)
: AsyncAbstractResponse(processorCallback) {
_code = 200; _code = 200;
_content = callback; _content = callback;
_contentLength = 0; _contentLength = 0;
@@ -647,7 +725,8 @@ size_t AsyncChunkedResponse::_fillBuffer(uint8_t *data, size_t len){
* Progmem Response * Progmem Response
* */ * */
AsyncProgmemResponse::AsyncProgmemResponse(int code, const String& contentType, const uint8_t * content, size_t len, AwsTemplateProcessor callback): AsyncAbstractResponse(callback) { AsyncProgmemResponse::AsyncProgmemResponse(int code, const String & contentType, const uint8_t * content, size_t len, AwsTemplateProcessor callback)
: AsyncAbstractResponse(callback) {
_code = code; _code = code;
_content = content; _content = content;
_contentType = contentType; _contentType = contentType;
@@ -667,13 +746,25 @@ size_t AsyncProgmemResponse::_fillBuffer(uint8_t *data, size_t len){
return left; return left;
} }
// added by proddy
AsyncResponse::AsyncResponse(const String & contentType, const uint8_t * content, size_t len)
: AsyncAbstractResponse(nullptr) {
_code = 200;
_content = content;
_contentType = contentType;
_contentLength = len;
_readLength = len;
}
size_t AsyncResponse::_fillBuffer(uint8_t * data, size_t len) {
memcpy(data, _content, len);
return 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;

View File

@@ -20,6 +20,7 @@
*/ */
#include "ESPAsyncWebServer.h" #include "ESPAsyncWebServer.h"
#include "WebHandlerImpl.h" #include "WebHandlerImpl.h"
#include "AsyncJson.h"
bool ON_STA_FILTER(AsyncWebServerRequest * request) { bool ON_STA_FILTER(AsyncWebServerRequest * request) {
return WiFi.localIP() == request->client()->localIP(); return WiFi.localIP() == request->client()->localIP();
@@ -38,12 +39,12 @@ const char *fs::FileOpenMode::append = "a";
AsyncWebServer::AsyncWebServer(uint16_t port) AsyncWebServer::AsyncWebServer(uint16_t port)
: _server(port) : _server(port)
, _rewrites(LinkedList<AsyncWebRewrite *>([](AsyncWebRewrite * r) { delete r; })) , _rewrites(LinkedList<AsyncWebRewrite *>([](AsyncWebRewrite * r) { delete r; }))
, _handlers(LinkedList<AsyncWebHandler*>([](AsyncWebHandler* h){ delete h; })) , _handlers(LinkedList<AsyncWebHandler *>([](AsyncWebHandler * h) { delete h; })) {
{
_catchAllHandler = new AsyncCallbackWebHandler(); _catchAllHandler = new AsyncCallbackWebHandler();
if (_catchAllHandler == NULL) if (_catchAllHandler == NULL)
return; return;
_server.onClient([](void *s, AsyncClient* c){ _server.onClient(
[](void * s, AsyncClient * c) {
if (c == NULL) if (c == NULL)
return; return;
c->setRxTimeout(3); c->setRxTimeout(3);
@@ -53,13 +54,15 @@ AsyncWebServer::AsyncWebServer(uint16_t port)
c->free(); c->free();
delete c; delete c;
} }
}, this); },
this);
} }
AsyncWebServer::~AsyncWebServer() { AsyncWebServer::~AsyncWebServer() {
reset(); reset();
end(); end();
if(_catchAllHandler) delete _catchAllHandler; if (_catchAllHandler)
delete _catchAllHandler;
} }
AsyncWebRewrite & AsyncWebServer::addRewrite(AsyncWebRewrite * rewrite) { AsyncWebRewrite & AsyncWebServer::addRewrite(AsyncWebRewrite * rewrite) {
@@ -129,7 +132,11 @@ void AsyncWebServer::_attachHandler(AsyncWebServerRequest *request){
} }
AsyncCallbackWebHandler& AsyncWebServer::on(const char* uri, WebRequestMethodComposite method, ArRequestHandlerFunction onRequest, ArUploadHandlerFunction onUpload, ArBodyHandlerFunction onBody){ AsyncCallbackWebHandler & AsyncWebServer::on(const char * uri,
WebRequestMethodComposite method,
ArRequestHandlerFunction onRequest,
ArUploadHandlerFunction onUpload,
ArBodyHandlerFunction onBody) {
AsyncCallbackWebHandler * handler = new AsyncCallbackWebHandler(); AsyncCallbackWebHandler * handler = new AsyncCallbackWebHandler();
handler->setUri(uri); handler->setUri(uri);
handler->setMethod(method); handler->setMethod(method);
@@ -140,7 +147,8 @@ AsyncCallbackWebHandler& AsyncWebServer::on(const char* uri, WebRequestMethodCom
return *handler; return *handler;
} }
AsyncCallbackWebHandler& AsyncWebServer::on(const char* uri, WebRequestMethodComposite method, ArRequestHandlerFunction onRequest, ArUploadHandlerFunction onUpload){ AsyncCallbackWebHandler &
AsyncWebServer::on(const char * uri, WebRequestMethodComposite method, ArRequestHandlerFunction onRequest, ArUploadHandlerFunction onUpload) {
AsyncCallbackWebHandler * handler = new AsyncCallbackWebHandler(); AsyncCallbackWebHandler * handler = new AsyncCallbackWebHandler();
handler->setUri(uri); handler->setUri(uri);
handler->setMethod(method); handler->setMethod(method);
@@ -167,6 +175,12 @@ AsyncCallbackWebHandler& AsyncWebServer::on(const char* uri, ArRequestHandlerFun
return *handler; return *handler;
} }
// added by proddy
void AsyncWebServer::on(const char * uri, ArJsonRequestHandlerFunction onRequest) {
auto * handler = new AsyncCallbackJsonWebHandler(uri, onRequest);
addHandler(handler);
}
AsyncStaticWebHandler & AsyncWebServer::serveStatic(const char * uri, fs::FS & fs, const char * path, const char * cache_control) { 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); AsyncStaticWebHandler * handler = new AsyncStaticWebHandler(uri, fs, path, cache_control);
addHandler(handler); addHandler(handler);
@@ -195,4 +209,3 @@ void AsyncWebServer::reset(){
_catchAllHandler->onBody(NULL); _catchAllHandler->onBody(NULL);
} }
} }

View File

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

View File

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

View File

@@ -36,7 +36,8 @@ ESP8266React::ESP8266React(AsyncWebServer * server, FS * fs)
return request->send(304); 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", "gzip");
// response->addHeader("Content-Encoding", "br"); // only works over HTTPS // response->addHeader("Content-Encoding", "br"); // only works over HTTPS
// response->addHeader("Cache-Control", "public, immutable, max-age=31536000"); // response->addHeader("Cache-Control", "public, immutable, max-age=31536000");

View File

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

View File

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

View File

@@ -24,9 +24,8 @@
#endif #endif
#define NTP_SETTINGS_FILE "/config/ntpSettings.json" #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" #define TIME_PATH "/rest/time"
class NTPSettings { class NTPSettings {
@@ -50,7 +49,6 @@ class NTPSettingsService : public StatefulService<NTPSettings> {
private: private:
HttpEndpoint<NTPSettings> _httpEndpoint; HttpEndpoint<NTPSettings> _httpEndpoint;
FSPersistence<NTPSettings> _fsPersistence; FSPersistence<NTPSettings> _fsPersistence;
AsyncCallbackJsonWebHandler _timeHandler;
bool _connected; bool _connected;
void WiFiEvent(WiFiEvent_t event); void WiFiEvent(WiFiEvent_t event);

View File

@@ -213,6 +213,7 @@ class AsyncWebServerResponse {
typedef std::function<void(AsyncWebServerRequest * request)> ArRequestHandlerFunction; 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, 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, 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 { class AsyncWebServer {
protected: protected:
@@ -232,6 +233,7 @@ class AsyncWebServer {
} }
void on(const char * uri, WebRequestMethodComposite method, ArRequestHandlerFunction onRequest){}; void on(const char * uri, WebRequestMethodComposite method, ArRequestHandlerFunction onRequest){};
void on(const char * uri, ArJsonRequestHandlerFunction onRequest){}; // added by proddy
}; };

View File

@@ -4,7 +4,7 @@
# The response will be shown in the right panel # The response will be shown in the right panel
@host = http://ems-esp.local @host = http://ems-esp.local
@host_dev = http://ems-esp2.local @host_dev = http://10.10.10.20
@token = eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6ImFkbWluIiwiYWRtaW4iOnRydWV9.2bHpWya2C7Q12WjNUBD6_7N3RCD7CMl-EGhyQVzFdDg @token = eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6ImFkbWluIiwiYWRtaW4iOnRydWV9.2bHpWya2C7Q12WjNUBD6_7N3RCD7CMl-EGhyQVzFdDg
@@ -95,3 +95,14 @@ Authorization: Bearer {{token}}
### ###
GET {{host_dev}}/api/system/commands GET {{host_dev}}/api/system/commands
###
POST {{host_dev}}/api/thermostat/seltemp
Content-Type: application/json
Authorization: Bearer {{token}}
{
"value" : 21.0
}
###
GET {{host_dev}}/api/thermostat/seltemp

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; uint16_t WebAPIService::api_fails_ = 0;
WebAPIService::WebAPIService(AsyncWebServer * server, SecurityManager * securityManager) WebAPIService::WebAPIService(AsyncWebServer * server, SecurityManager * securityManager)
: _securityManager(securityManager) : _securityManager(securityManager) {
, _apiHandler(EMSESP_API_SERVICE_PATH, [this](AsyncWebServerRequest * request, JsonVariant json) { webAPIService_post(request, json); }) { // for POSTs // API
server->on(EMSESP_API_SERVICE_PATH, HTTP_GET, [this](AsyncWebServerRequest * request) { webAPIService_get(request); }); // for GETs server->on(EMSESP_API_SERVICE_PATH, [this](AsyncWebServerRequest * request, JsonVariant json) { webAPIService(request, json); });
server->addHandler(&_apiHandler);
// for settings // settings
server->on(GET_SETTINGS_PATH, server->on(GET_SETTINGS_PATH,
HTTP_GET, HTTP_GET,
securityManager->wrapRequest([this](AsyncWebServerRequest * request) { getSettings(request); }, AuthenticationPredicates::IS_ADMIN)); 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)); securityManager->wrapRequest([this](AsyncWebServerRequest * request) { getEntities(request); }, AuthenticationPredicates::IS_ADMIN));
} }
// HTTP GET // POST|GET /{device}
// GET /{device} // POST|GET /{device}/{entity}
// GET /{device}/{entity} void WebAPIService::webAPIService(AsyncWebServerRequest * request, JsonVariant json) {
void WebAPIService::webAPIService_get(AsyncWebServerRequest * request) { JsonObject input;
// 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) {
// if no body then treat it as a secure GET // if no body then treat it as a secure GET
if (!json.is<JsonObject>()) { if ((request->method() == HTTP_GET) || (!json.is<JsonObject>())) {
webAPIService_get(request); // HTTP GET
return; 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(request, input);
} }
// parse the URL looking for query or path parameters // parse the URL looking for query or path parameters
// reporting back any errors // reporting back any errors
void WebAPIService::parse(AsyncWebServerRequest * request, JsonObject input) { 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 // check for query parameters first, the old style from v2
// api?device={device}&cmd={name}&data={value}&id={hc} // api?device={device}&cmd={name}&data={value}&id={hc}
if (request->url() == "/api") { if (request->url() == EMSESP_API_SERVICE_PATH) {
// get the device // get the device
if (request->hasParam(F_(device))) { if (request->hasParam(F_(device))) {
input["device"] = request->getParam(F_(device))->value().c_str(); input["device"] = request->getParam(F_(device))->value().c_str();

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -66,8 +66,6 @@ class WebLogService : public uuid::log::Handler {
void setValues(AsyncWebServerRequest * request, JsonVariant json); void setValues(AsyncWebServerRequest * request, JsonVariant json);
AsyncCallbackJsonWebHandler setValues_; // for POSTs
uint64_t last_transmit_ = 0; // Last transmit time 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 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 size_t limit_log_messages_ = 1; // dynamic limit