From 7941e944da9db83db87e2ad8eb74c2f5f588015e Mon Sep 17 00:00:00 2001 From: Jack Jansen Date: Mon, 16 Dec 2019 14:30:03 +0100 Subject: [PATCH 01/54] Different way of HTTPMethod->string mapping, original one didn't work for GET (for reasons I don't understand) --- src/ESPWebServer.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ESPWebServer.cpp b/src/ESPWebServer.cpp index 5b961b3..4941a18 100644 --- a/src/ESPWebServer.cpp +++ b/src/ESPWebServer.cpp @@ -65,8 +65,8 @@ void ESPWebServer::on(const String &uri, THandlerFunction handler) { void ESPWebServer::on(const String &uri, HTTPMethod method, THandlerFunction fn) { // TODO: Handle HTTP_ANY - char *methodname = METHODNAMES[0].text; - for (size_t n = 1; n < sizeof(METHODNAMES); n++) { + char *methodname = "???"; + for (size_t n = 0; n < sizeof(METHODNAMES); n++) { if (METHODNAMES[n].val == method) { methodname = METHODNAMES[n].text; break; From 40889be0a9b767614ab0e11cbdff3559e7d5e5e7 Mon Sep 17 00:00:00 2001 From: Jack Jansen Date: Mon, 16 Dec 2019 17:40:17 +0100 Subject: [PATCH 02/54] Print message when calling unimplemented method --- src/ESPWebServer.cpp | 48 ++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 44 insertions(+), 4 deletions(-) diff --git a/src/ESPWebServer.cpp b/src/ESPWebServer.cpp index 4941a18..26bb8c3 100644 --- a/src/ESPWebServer.cpp +++ b/src/ESPWebServer.cpp @@ -45,6 +45,7 @@ void ESPWebServer::handleClient() { void ESPWebServer::close() { // TODO + HTTPS_LOGE("close() not yet implemented"); } void ESPWebServer::stop() { @@ -52,11 +53,13 @@ void ESPWebServer::stop() { } bool ESPWebServer::authenticate(const char * username, const char * password) { + HTTPS_LOGE("authenticate() not yet implemented"); return false; } void ESPWebServer::requestAuthentication(HTTPAuthMethod mode, const char* realm, const String& authFailMsg) { // TODO + HTTPS_LOGE("requestAuthentication() not yet implemented"); } void ESPWebServer::on(const String &uri, THandlerFunction handler) { @@ -79,10 +82,12 @@ void ESPWebServer::on(const String &uri, HTTPMethod method, THandlerFunction fn) void ESPWebServer::on(const String &uri, HTTPMethod method, THandlerFunction fn, THandlerFunction ufn) { // TODO // ufn handles uploads + HTTPS_LOGE("on() for upload not yet implemented"); } void ESPWebServer::serveStatic(const char* uri, fs::FS& fs, const char* path, const char* cache_header) { // TODO + HTTPS_LOGE("serveStatic() not yet implemented"); } void ESPWebServer::onNotFound(THandlerFunction fn) { @@ -95,6 +100,7 @@ void ESPWebServer::onNotFound(THandlerFunction fn) { void ESPWebServer::onFileUpload(THandlerFunction fn) { // TODO + HTTPS_LOGE("onFileUpload() not yet implemented"); } String ESPWebServer::uri() { @@ -113,70 +119,94 @@ HTTPMethod ESPWebServer::method() { HTTPUpload& ESPWebServer::upload() { // TODO HTTPUpload upload; + HTTPS_LOGE("upload() not yet implemented"); return upload; } String ESPWebServer::pathArg(unsigned int i) { // TODO + HTTPS_LOGE("pathArg() not yet implemented"); return ""; } String ESPWebServer::arg(String name) { - // TODO - return ""; + if (!_activeRequest) { + HTTPS_LOGE("arg() called but no _activeRequest"); + return ""; + } + ResourceParameters *params = _activeRequest->getParams(); + std::string value = params->getRequestParameter(std::string(name.c_str())); + HTTPS_LOGD("arg(%s) returns %s", name.c_str(), value.c_str()); + return String(value.c_str()); } String ESPWebServer::arg(int i) { // TODO + HTTPS_LOGE("arg(int) not yet implemented"); return ""; } String ESPWebServer::argName(int i) { // TODO + HTTPS_LOGE("argName() not yet implemented"); return ""; } int ESPWebServer::args() { // TODO + HTTPS_LOGE("args() not yet implemented"); return 0; } bool ESPWebServer::hasArg(String name) { - // TODO - return false; + if (!_activeRequest) { + HTTPS_LOGE("hasArg() called but no _activeRequest"); + return false; + } + ResourceParameters *params = _activeRequest->getParams(); + bool rv = params->isRequestParameterSet(std::string(name.c_str())); + HTTPS_LOGD("hasArg(%s) returns %d", name.c_str(), (int)rv); + return rv; } void ESPWebServer::collectHeaders(const char* headerKeys[], const size_t headerKeysCount) { // TODO + HTTPS_LOGE("collectHeaders() not yet implemented"); } String ESPWebServer::header(String name) { // TODO + HTTPS_LOGE("header(String) not yet implemented"); return ""; } String ESPWebServer::header(int i) { // TODO + HTTPS_LOGE("header(int) not yet implemented"); return ""; } String ESPWebServer::headerName(int i) { // TODO + HTTPS_LOGE("headerName() not yet implemented"); return ""; } int ESPWebServer::headers() { // TODO + HTTPS_LOGE("headers() not yet implemented"); return 0; } bool ESPWebServer::hasHeader(String name) { // TODO + HTTPS_LOGE("hasHeader() not yet implemented"); return false; } String ESPWebServer::hostHeader() { // TODO + HTTPS_LOGE("hostHeader() not yet implemented"); return ""; } @@ -196,42 +226,52 @@ void ESPWebServer::send(int code, const String& content_type, const String& cont void ESPWebServer::send_P(int code, PGM_P content_type, PGM_P content) { // TODO + HTTPS_LOGE("send_P() not yet implemented"); } void ESPWebServer::send_P(int code, PGM_P content_type, PGM_P content, size_t contentLength) { // TODO + HTTPS_LOGE("send_P() not yet implemented"); } void ESPWebServer::enableCORS(boolean value) { // TODO + HTTPS_LOGE("enableCORS() not yet implemented"); } void ESPWebServer::enableCrossOrigin(boolean value) { // TODO + HTTPS_LOGE("enableCrossOrigin() not yet implemented"); } void ESPWebServer::setContentLength(const size_t contentLength) { // TODO + HTTPS_LOGE("setContentLength() not yet implemented"); } void ESPWebServer::sendHeader(const String& name, const String& value, bool first) { // TODO + HTTPS_LOGE("sendHeader() not yet implemented"); } void ESPWebServer::sendContent(const String& content) { // TODO + HTTPS_LOGE("sendContent() not yet implemented"); } void ESPWebServer::sendContent_P(PGM_P content) { // TODO + HTTPS_LOGE("sendContent_P() not yet implemented"); } void ESPWebServer::sendContent_P(PGM_P content, size_t size) { // TODO + HTTPS_LOGE("sendContent_P() not yet implemented"); } String ESPWebServer::urlDecode(const String& text) { // TODO + HTTPS_LOGE("urlDecode() not yet implemented"); return text; } From 21b5c602660e2eb608ba9bf989d767cb8e29f167 Mon Sep 17 00:00:00 2001 From: Jack Jansen Date: Fri, 20 Dec 2019 21:52:09 +0100 Subject: [PATCH 03/54] Added temporary platformio.ini to build the example (for easier testing) --- platformio.ini | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 platformio.ini diff --git a/platformio.ini b/platformio.ini new file mode 100644 index 0000000..02aedb5 --- /dev/null +++ b/platformio.ini @@ -0,0 +1,10 @@ +[platformio] +default_envs = lolin32 + +[env:lolin32] +framework = arduino +platform = espressif32@>=1.11 +board = lolin32 +lib_ldf_mode = deep+ +lib_deps = esp32_https_server +src_filter = +<*> +<../examples/HelloServer> From 234df9b5ad0b0f4ba0350b7d9b2cb4fc7e475e99 Mon Sep 17 00:00:00 2001 From: Jack Jansen Date: Fri, 20 Dec 2019 21:52:24 +0100 Subject: [PATCH 04/54] Added a few more methods --- src/ESPWebServer.cpp | 31 +++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/src/ESPWebServer.cpp b/src/ESPWebServer.cpp index 26bb8c3..3515fc3 100644 --- a/src/ESPWebServer.cpp +++ b/src/ESPWebServer.cpp @@ -68,7 +68,7 @@ void ESPWebServer::on(const String &uri, THandlerFunction handler) { void ESPWebServer::on(const String &uri, HTTPMethod method, THandlerFunction fn) { // TODO: Handle HTTP_ANY - char *methodname = "???"; + const char *methodname = "???"; for (size_t n = 0; n < sizeof(METHODNAMES); n++) { if (METHODNAMES[n].val == method) { methodname = METHODNAMES[n].text; @@ -118,7 +118,7 @@ HTTPMethod ESPWebServer::method() { HTTPUpload& ESPWebServer::upload() { // TODO - HTTPUpload upload; + static HTTPUpload upload; HTTPS_LOGE("upload() not yet implemented"); return upload; } @@ -225,13 +225,17 @@ void ESPWebServer::send(int code, const String& content_type, const String& cont } void ESPWebServer::send_P(int code, PGM_P content_type, PGM_P content) { - // TODO - HTTPS_LOGE("send_P() not yet implemented"); + _activeResponse->setStatusCode(code); + String memContentType(FPSTR(content_type)); + _activeResponse->setHeader("Content-Type", memContentType.c_str()); + _activeResponse->print(FPSTR(content)); } void ESPWebServer::send_P(int code, PGM_P content_type, PGM_P content, size_t contentLength) { - // TODO - HTTPS_LOGE("send_P() not yet implemented"); + _activeResponse->setStatusCode(code); + String memContentType(FPSTR(content_type)); + _activeResponse->setHeader("Content-Type", memContentType.c_str()); + _activeResponse->write((const uint8_t *)content, contentLength); } void ESPWebServer::enableCORS(boolean value) { @@ -250,23 +254,22 @@ void ESPWebServer::setContentLength(const size_t contentLength) { } void ESPWebServer::sendHeader(const String& name, const String& value, bool first) { - // TODO - HTTPS_LOGE("sendHeader() not yet implemented"); + if (first) { + HTTPS_LOGW("sendHeader(..., first=true) not implemented"); + } + _activeResponse->setHeader(name.c_str(), value.c_str()); } void ESPWebServer::sendContent(const String& content) { - // TODO - HTTPS_LOGE("sendContent() not yet implemented"); + _activeResponse->print(content); } void ESPWebServer::sendContent_P(PGM_P content) { - // TODO - HTTPS_LOGE("sendContent_P() not yet implemented"); + _activeResponse->print(FPSTR(content)); } void ESPWebServer::sendContent_P(PGM_P content, size_t size) { - // TODO - HTTPS_LOGE("sendContent_P() not yet implemented"); + _activeResponse->write((const uint8_t *)content, size); } String ESPWebServer::urlDecode(const String& text) { From 7ef82c5c89adc8d3ee6279654b067198cbbaa3a8 Mon Sep 17 00:00:00 2001 From: Jack Jansen Date: Sat, 21 Dec 2019 15:23:33 +0100 Subject: [PATCH 05/54] Implemented Content-Length and CORS headers --- src/ESPWebServer.cpp | 29 ++++++++++++++++++++++------- src/ESPWebServer.hpp | 10 ++++++++++ 2 files changed, 32 insertions(+), 7 deletions(-) diff --git a/src/ESPWebServer.cpp b/src/ESPWebServer.cpp index 3515fc3..b81d23a 100644 --- a/src/ESPWebServer.cpp +++ b/src/ESPWebServer.cpp @@ -1,5 +1,6 @@ #include "ESPWebServer.hpp" +#include using namespace httpsserver; @@ -20,7 +21,10 @@ struct { }; ESPWebServer::ESPWebServer(IPAddress addr, int port) : - _server(HTTPServer(port, 4, addr)) { + _server(HTTPServer(port, 4, addr)), + _corsEnabled(false), + _contentLength(0) +{ _notFoundNode = nullptr; } @@ -211,8 +215,10 @@ String ESPWebServer::hostHeader() { } void ESPWebServer::send(int code, const char* content_type, const String& content) { + _contentLength = content.length(); _activeResponse->setStatusCode(code); _activeResponse->setHeader("Content-Type", content_type); + _standardHeaders(); _activeResponse->print(content); } @@ -225,32 +231,40 @@ void ESPWebServer::send(int code, const String& content_type, const String& cont } void ESPWebServer::send_P(int code, PGM_P content_type, PGM_P content) { + _contentLength = strlen_P(content); _activeResponse->setStatusCode(code); String memContentType(FPSTR(content_type)); _activeResponse->setHeader("Content-Type", memContentType.c_str()); + _standardHeaders(); _activeResponse->print(FPSTR(content)); } void ESPWebServer::send_P(int code, PGM_P content_type, PGM_P content, size_t contentLength) { + _contentLength = contentLength; _activeResponse->setStatusCode(code); String memContentType(FPSTR(content_type)); _activeResponse->setHeader("Content-Type", memContentType.c_str()); + _standardHeaders(); _activeResponse->write((const uint8_t *)content, contentLength); } +void ESPWebServer::_standardHeaders() { + if (_corsEnabled) _activeResponse->setHeader("Access-Control-Allow-Origin", "*"); + if (_contentLength != CONTENT_LENGTH_NOT_SET && _contentLength != CONTENT_LENGTH_UNKNOWN) { + _activeResponse->setHeader("Content-Length", String(_contentLength).c_str()); + } +} + void ESPWebServer::enableCORS(boolean value) { - // TODO - HTTPS_LOGE("enableCORS() not yet implemented"); + _corsEnabled = value; } void ESPWebServer::enableCrossOrigin(boolean value) { - // TODO - HTTPS_LOGE("enableCrossOrigin() not yet implemented"); + _corsEnabled = value; } void ESPWebServer::setContentLength(const size_t contentLength) { - // TODO - HTTPS_LOGE("setContentLength() not yet implemented"); + _contentLength = contentLength; } void ESPWebServer::sendHeader(const String& name, const String& value, bool first) { @@ -284,6 +298,7 @@ void ESPWebServer::_handlerWrapper( ESPWebServerNode *node = (ESPWebServerNode*)req->getResolvedNode(); node->_wrapper->_activeRequest = req; node->_wrapper->_activeResponse = res; + node->_wrapper->_contentLength = CONTENT_LENGTH_NOT_SET; node->_wrappedHandler(); node->_wrapper->_activeRequest = nullptr; node->_wrapper->_activeResponse = nullptr; diff --git a/src/ESPWebServer.hpp b/src/ESPWebServer.hpp index 2b4a596..c05282f 100644 --- a/src/ESPWebServer.hpp +++ b/src/ESPWebServer.hpp @@ -22,6 +22,9 @@ enum HTTPAuthMethod { BASIC_AUTH, /* DIGEST_AUTH */ }; #define HTTP_UPLOAD_BUFLEN 1436 #endif +#define CONTENT_LENGTH_UNKNOWN ((size_t) -1) +#define CONTENT_LENGTH_NOT_SET ((size_t) -2) + typedef std::function THandlerFunction; typedef struct { @@ -111,6 +114,9 @@ class ESPWebServer /** The wrapper function that maps on() calls */ static void _handlerWrapper(httpsserver::HTTPRequest *req, httpsserver::HTTPResponse *res); + /** Add standard headers */ + void _standardHeaders(); + /** The backing server instance */ httpsserver::HTTPServer _server; @@ -120,6 +126,10 @@ class ESPWebServer /** default node */ ESPWebServerNode *_notFoundNode; + + /** Instance variables for standard headers */ + bool _corsEnabled; + size_t _contentLength; }; class ESPWebServerNode : public httpsserver::ResourceNode { From 8407ea768b7507b52e1c29f29d98e5880af24297 Mon Sep 17 00:00:00 2001 From: Jack Jansen Date: Sat, 21 Dec 2019 15:53:27 +0100 Subject: [PATCH 06/54] Do enableCORS differently --- src/ESPWebServer.cpp | 20 ++++++++++++-------- src/ESPWebServer.hpp | 1 - 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/src/ESPWebServer.cpp b/src/ESPWebServer.cpp index b81d23a..d12daa3 100644 --- a/src/ESPWebServer.cpp +++ b/src/ESPWebServer.cpp @@ -22,7 +22,6 @@ struct { ESPWebServer::ESPWebServer(IPAddress addr, int port) : _server(HTTPServer(port, 4, addr)), - _corsEnabled(false), _contentLength(0) { _notFoundNode = nullptr; @@ -48,8 +47,7 @@ void ESPWebServer::handleClient() { } void ESPWebServer::close() { - // TODO - HTTPS_LOGE("close() not yet implemented"); + _server.stop(); } void ESPWebServer::stop() { @@ -62,8 +60,15 @@ bool ESPWebServer::authenticate(const char * username, const char * password) { } void ESPWebServer::requestAuthentication(HTTPAuthMethod mode, const char* realm, const String& authFailMsg) { - // TODO - HTTPS_LOGE("requestAuthentication() not yet implemented"); + if (realm == NULL) realm = "Login Required"; + if (mode == BASIC_AUTH) { + std::string authArg = "Basic realm=\""; + authArg += realm; + authArg += "\""; + _activeResponse->setHeader("WWW-Authenticate", authArg); + } else { + HTTPS_LOGE("Only BASIC_AUTH implemented"); + } } void ESPWebServer::on(const String &uri, THandlerFunction handler) { @@ -249,18 +254,17 @@ void ESPWebServer::send_P(int code, PGM_P content_type, PGM_P content, size_t co } void ESPWebServer::_standardHeaders() { - if (_corsEnabled) _activeResponse->setHeader("Access-Control-Allow-Origin", "*"); if (_contentLength != CONTENT_LENGTH_NOT_SET && _contentLength != CONTENT_LENGTH_UNKNOWN) { _activeResponse->setHeader("Content-Length", String(_contentLength).c_str()); } } void ESPWebServer::enableCORS(boolean value) { - _corsEnabled = value; + if (value) _server.setDefaultHeader("Access-Control-Allow-Origin", "*"); } void ESPWebServer::enableCrossOrigin(boolean value) { - _corsEnabled = value; + enableCORS(value); } void ESPWebServer::setContentLength(const size_t contentLength) { diff --git a/src/ESPWebServer.hpp b/src/ESPWebServer.hpp index c05282f..58313c9 100644 --- a/src/ESPWebServer.hpp +++ b/src/ESPWebServer.hpp @@ -128,7 +128,6 @@ class ESPWebServer ESPWebServerNode *_notFoundNode; /** Instance variables for standard headers */ - bool _corsEnabled; size_t _contentLength; }; From 07052269114caeea253335002f0ce7cff8f12341 Mon Sep 17 00:00:00 2001 From: Jack Jansen Date: Sat, 21 Dec 2019 16:53:44 +0100 Subject: [PATCH 07/54] Started on implementing serveStatic() --- src/ESPWebServer.cpp | 34 ++++++++++++++++++++++++++++++++-- src/ESPWebServer.hpp | 22 ++++++++++++++++++++++ 2 files changed, 54 insertions(+), 2 deletions(-) diff --git a/src/ESPWebServer.cpp b/src/ESPWebServer.cpp index d12daa3..c5bcf9b 100644 --- a/src/ESPWebServer.cpp +++ b/src/ESPWebServer.cpp @@ -95,8 +95,8 @@ void ESPWebServer::on(const String &uri, HTTPMethod method, THandlerFunction fn, } void ESPWebServer::serveStatic(const char* uri, fs::FS& fs, const char* path, const char* cache_header) { - // TODO - HTTPS_LOGE("serveStatic() not yet implemented"); + ESPWebServerStaticNode *node = new ESPWebServerStaticNode(this, std::string(path), fs, path, cache_header); + _server.registerNode(node); } void ESPWebServer::onNotFound(THandlerFunction fn) { @@ -323,3 +323,33 @@ ESPWebServerNode::ESPWebServerNode( ESPWebServerNode::~ESPWebServerNode() { } + +ESPWebServerStaticNode::ESPWebServerStaticNode( + ESPWebServer *server, + const std::string &path, + FS& fs, + const char *filePath, + const char *cache_header) +: ResourceNode(path, "GET", &(ESPWebServerStaticNode::_handlerWrapper), ""), + _fs(fs), + _filePath(filePath), + _cache_header(cache_header), + _isFile(false) +{ + _isFile = _fs.exists(filePath); +} + +void ESPWebServerStaticNode::_handler(httpsserver::HTTPRequest *req, httpsserver::HTTPResponse *res) { + HTTPS_LOGE("static not yet implemented path=%s filePath=%s\n", _path.c_str(), _filePath); +} + +void ESPWebServerStaticNode::_handlerWrapper(httpsserver::HTTPRequest *req, httpsserver::HTTPResponse *res) { + ESPWebServerStaticNode *node = (ESPWebServerStaticNode*)req->getResolvedNode(); + node->_handler(req, res); +} + + +ESPWebServerStaticNode::~ESPWebServerStaticNode() { + +} + diff --git a/src/ESPWebServer.hpp b/src/ESPWebServer.hpp index 58313c9..b6d6cf0 100644 --- a/src/ESPWebServer.hpp +++ b/src/ESPWebServer.hpp @@ -5,6 +5,7 @@ #include #include +#include #include #include @@ -147,4 +148,25 @@ class ESPWebServerNode : public httpsserver::ResourceNode { const THandlerFunction _wrappedHandler; }; +class ESPWebServerStaticNode : public httpsserver::ResourceNode { +public: + ESPWebServerStaticNode( + ESPWebServer *server, + const std::string &path, + FS& fs, + const char *filePath, + const char *cache_header); + virtual ~ESPWebServerStaticNode(); + +protected: + static void _handlerWrapper(httpsserver::HTTPRequest *req, httpsserver::HTTPResponse *res); + void _handler(httpsserver::HTTPRequest *req, httpsserver::HTTPResponse *res); + friend class ESPWebServer; + ESPWebServer *_wrapper; + FS& _fs; + const char *_filePath; + const char *_cache_header; + bool _isFile; +}; + #endif //ESPWEBSERVER_H \ No newline at end of file From 2af21f7ae590166436e82f127b43213b05aa2311 Mon Sep 17 00:00:00 2001 From: Jack Jansen Date: Sat, 21 Dec 2019 17:35:27 +0100 Subject: [PATCH 08/54] Getting started on uploadHandler --- src/ESPWebServer.cpp | 26 +++++++++++--------------- src/ESPWebServer.hpp | 6 ++++++ 2 files changed, 17 insertions(+), 15 deletions(-) diff --git a/src/ESPWebServer.cpp b/src/ESPWebServer.cpp index c5bcf9b..d1d085e 100644 --- a/src/ESPWebServer.cpp +++ b/src/ESPWebServer.cpp @@ -76,6 +76,10 @@ void ESPWebServer::on(const String &uri, THandlerFunction handler) { } void ESPWebServer::on(const String &uri, HTTPMethod method, THandlerFunction fn) { + on(uri, method, fn, _uploadHandler); +} + +void ESPWebServer::on(const String &uri, HTTPMethod method, THandlerFunction fn, THandlerFunction ufn) { // TODO: Handle HTTP_ANY const char *methodname = "???"; for (size_t n = 0; n < sizeof(METHODNAMES); n++) { @@ -84,16 +88,10 @@ void ESPWebServer::on(const String &uri, HTTPMethod method, THandlerFunction fn) break; } } - ESPWebServerNode *node = new ESPWebServerNode(this,std::string(uri.c_str()), std::string(methodname),fn); + ESPWebServerNode *node = new ESPWebServerNode(this,std::string(uri.c_str()), std::string(methodname),fn, ufn); _server.registerNode(node); } -void ESPWebServer::on(const String &uri, HTTPMethod method, THandlerFunction fn, THandlerFunction ufn) { - // TODO - // ufn handles uploads - HTTPS_LOGE("on() for upload not yet implemented"); -} - void ESPWebServer::serveStatic(const char* uri, fs::FS& fs, const char* path, const char* cache_header) { ESPWebServerStaticNode *node = new ESPWebServerStaticNode(this, std::string(path), fs, path, cache_header); _server.registerNode(node); @@ -103,13 +101,12 @@ void ESPWebServer::onNotFound(THandlerFunction fn) { if (_notFoundNode != nullptr) { delete _notFoundNode; } - _notFoundNode = new ESPWebServerNode(this, "", "", fn); + _notFoundNode = new ESPWebServerNode(this, "", "", fn, THandlerFunction()); _server.setDefaultNode(_notFoundNode); } void ESPWebServer::onFileUpload(THandlerFunction fn) { - // TODO - HTTPS_LOGE("onFileUpload() not yet implemented"); + _uploadHandler = fn; } String ESPWebServer::uri() { @@ -126,10 +123,7 @@ HTTPMethod ESPWebServer::method() { } HTTPUpload& ESPWebServer::upload() { - // TODO - static HTTPUpload upload; - HTTPS_LOGE("upload() not yet implemented"); - return upload; + return *_activeUpload; } String ESPWebServer::pathArg(unsigned int i) { @@ -313,10 +307,12 @@ ESPWebServerNode::ESPWebServerNode( const std::string &path, const std::string &method, const THandlerFunction &handler, + const THandlerFunction &uploadHandler, const std::string &tag) : ResourceNode(path, method, &(ESPWebServer::_handlerWrapper), tag), _wrapper(server), - _wrappedHandler(handler) { + _wrappedHandler(handler), + _wrappedUploadHandler(uploadHandler) { } diff --git a/src/ESPWebServer.hpp b/src/ESPWebServer.hpp index b6d6cf0..ccdbdba 100644 --- a/src/ESPWebServer.hpp +++ b/src/ESPWebServer.hpp @@ -124,12 +124,16 @@ class ESPWebServer /** The currently active request */ httpsserver::HTTPRequest *_activeRequest; httpsserver::HTTPResponse *_activeResponse; + HTTPUpload *_activeUpload; /** default node */ ESPWebServerNode *_notFoundNode; /** Instance variables for standard headers */ size_t _contentLength; + + /** Default file upload handler */ + THandlerFunction _uploadHandler; }; class ESPWebServerNode : public httpsserver::ResourceNode { @@ -139,6 +143,7 @@ class ESPWebServerNode : public httpsserver::ResourceNode { const std::string &path, const std::string &method, const THandlerFunction &handler, + const THandlerFunction &uploadHandler, const std::string &tag = ""); virtual ~ESPWebServerNode(); @@ -146,6 +151,7 @@ class ESPWebServerNode : public httpsserver::ResourceNode { friend class ESPWebServer; ESPWebServer *_wrapper; const THandlerFunction _wrappedHandler; + const THandlerFunction _wrappedUploadHandler; }; class ESPWebServerStaticNode : public httpsserver::ResourceNode { From 4a2e7c22c98f63106cf516365d455a10b64754c1 Mon Sep 17 00:00:00 2001 From: Jack Jansen Date: Sat, 21 Dec 2019 22:54:13 +0100 Subject: [PATCH 09/54] Switching to forked esp32_https_server, which has feature/request_param_parsing branch merged already and HTTPRequest::getHTTPHeaders() --- library.json | 2 +- platformio.ini | 2 +- src/ESPWebServer.cpp | 5 +++-- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/library.json b/library.json index b3240f7..e262284 100644 --- a/library.json +++ b/library.json @@ -17,7 +17,7 @@ "dependencies": [ { "name": "esp32_https_server", - "version": "0.3.0" + "version": "https://github.com/jackjansen/esp32_https_server.git#exp-jack-compat" } ], "license": "MIT", diff --git a/platformio.ini b/platformio.ini index 02aedb5..504f2b1 100644 --- a/platformio.ini +++ b/platformio.ini @@ -6,5 +6,5 @@ framework = arduino platform = espressif32@>=1.11 board = lolin32 lib_ldf_mode = deep+ -lib_deps = esp32_https_server +lib_deps = https://github.com/jackjansen/esp32_https_server.git#exp-jack-compat src_filter = +<*> +<../examples/HelloServer> diff --git a/src/ESPWebServer.cpp b/src/ESPWebServer.cpp index d1d085e..db0374b 100644 --- a/src/ESPWebServer.cpp +++ b/src/ESPWebServer.cpp @@ -138,7 +138,8 @@ String ESPWebServer::arg(String name) { return ""; } ResourceParameters *params = _activeRequest->getParams(); - std::string value = params->getRequestParameter(std::string(name.c_str())); + std::string value; + params->getQueryParameter(std::string(name.c_str()), value); HTTPS_LOGD("arg(%s) returns %s", name.c_str(), value.c_str()); return String(value.c_str()); } @@ -167,7 +168,7 @@ bool ESPWebServer::hasArg(String name) { return false; } ResourceParameters *params = _activeRequest->getParams(); - bool rv = params->isRequestParameterSet(std::string(name.c_str())); + bool rv = params->isQueryParameterSet(std::string(name.c_str())); HTTPS_LOGD("hasArg(%s) returns %d", name.c_str(), (int)rv); return rv; } From 018fcab6a4ea4cb1c03311b9c0e27e6b5801c824 Mon Sep 17 00:00:00 2001 From: Jack Jansen Date: Sat, 21 Dec 2019 22:56:32 +0100 Subject: [PATCH 10/54] Removed code to test that we're actually in a request: the original WebServer.h also simply crashes when you call the methods at the wrong time --- src/ESPWebServer.cpp | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/ESPWebServer.cpp b/src/ESPWebServer.cpp index db0374b..b64d7f2 100644 --- a/src/ESPWebServer.cpp +++ b/src/ESPWebServer.cpp @@ -133,10 +133,6 @@ String ESPWebServer::pathArg(unsigned int i) { } String ESPWebServer::arg(String name) { - if (!_activeRequest) { - HTTPS_LOGE("arg() called but no _activeRequest"); - return ""; - } ResourceParameters *params = _activeRequest->getParams(); std::string value; params->getQueryParameter(std::string(name.c_str()), value); @@ -163,10 +159,6 @@ int ESPWebServer::args() { } bool ESPWebServer::hasArg(String name) { - if (!_activeRequest) { - HTTPS_LOGE("hasArg() called but no _activeRequest"); - return false; - } ResourceParameters *params = _activeRequest->getParams(); bool rv = params->isQueryParameterSet(std::string(name.c_str())); HTTPS_LOGD("hasArg(%s) returns %d", name.c_str(), (int)rv); From 90aae153b676bebd0d62fc0b906ebae5fda9ad53 Mon Sep 17 00:00:00 2001 From: Jack Jansen Date: Sat, 21 Dec 2019 23:12:42 +0100 Subject: [PATCH 11/54] Implemented integer-based arg() interfaces --- src/ESPWebServer.cpp | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/src/ESPWebServer.cpp b/src/ESPWebServer.cpp index b64d7f2..1685641 100644 --- a/src/ESPWebServer.cpp +++ b/src/ESPWebServer.cpp @@ -141,21 +141,28 @@ String ESPWebServer::arg(String name) { } String ESPWebServer::arg(int i) { - // TODO - HTTPS_LOGE("arg(int) not yet implemented"); + ResourceParameters *params = _activeRequest->getParams(); + int idx=0; + for (auto it=params->beginQueryParameters(); it != params->endQueryParameters(); it++, idx++) { + if (idx == i) + return String(it->second.c_str()); + } return ""; } String ESPWebServer::argName(int i) { - // TODO - HTTPS_LOGE("argName() not yet implemented"); + ResourceParameters *params = _activeRequest->getParams(); + int idx=0; + for (auto it=params->beginQueryParameters(); it != params->endQueryParameters(); it++, idx++) { + if (idx == i) + return String(it->first.c_str()); + } return ""; } int ESPWebServer::args() { - // TODO - HTTPS_LOGE("args() not yet implemented"); - return 0; + ResourceParameters *params = _activeRequest->getParams(); + return params->getQueryParameterCount(); } bool ESPWebServer::hasArg(String name) { From 4c5dc83a650d972d807999325237fc8936f6956f Mon Sep 17 00:00:00 2001 From: Jack Jansen Date: Sat, 21 Dec 2019 23:44:23 +0100 Subject: [PATCH 12/54] Implemented access to headers --- src/ESPWebServer.cpp | 55 ++++++++++++++++++++++++++------------------ 1 file changed, 32 insertions(+), 23 deletions(-) diff --git a/src/ESPWebServer.cpp b/src/ESPWebServer.cpp index 1685641..8377133 100644 --- a/src/ESPWebServer.cpp +++ b/src/ESPWebServer.cpp @@ -81,6 +81,7 @@ void ESPWebServer::on(const String &uri, HTTPMethod method, THandlerFunction fn) void ESPWebServer::on(const String &uri, HTTPMethod method, THandlerFunction fn, THandlerFunction ufn) { // TODO: Handle HTTP_ANY + // TODO: convert {} in uri to * (so pathArg() will work) const char *methodname = "???"; for (size_t n = 0; n < sizeof(METHODNAMES); n++) { if (METHODNAMES[n].val == method) { @@ -93,6 +94,7 @@ void ESPWebServer::on(const String &uri, HTTPMethod method, THandlerFunction fn, } void ESPWebServer::serveStatic(const char* uri, fs::FS& fs, const char* path, const char* cache_header) { + // TODO: add * or something to path so serveStatic("/dir/",...) will serve all content from that directory ESPWebServerStaticNode *node = new ESPWebServerStaticNode(this, std::string(path), fs, path, cache_header); _server.registerNode(node); } @@ -127,9 +129,9 @@ HTTPUpload& ESPWebServer::upload() { } String ESPWebServer::pathArg(unsigned int i) { - // TODO - HTTPS_LOGE("pathArg() not yet implemented"); - return ""; + ResourceParameters *params = _activeRequest->getParams(); + auto rv = params->getPathParameter(i); + return String(rv.c_str()); } String ESPWebServer::arg(String name) { @@ -173,44 +175,52 @@ bool ESPWebServer::hasArg(String name) { } void ESPWebServer::collectHeaders(const char* headerKeys[], const size_t headerKeysCount) { - // TODO - HTTPS_LOGE("collectHeaders() not yet implemented"); + HTTPS_LOGW("collectHeaders() not implemented, but probably not needed"); } String ESPWebServer::header(String name) { - // TODO - HTTPS_LOGE("header(String) not yet implemented"); + HTTPHeaders* headers = _activeRequest->getHTTPHeaders(); + HTTPHeader* header = headers->get(std::string(name.c_str())); + if (header) { + return String(header->_value.c_str()); + } return ""; } String ESPWebServer::header(int i) { - // TODO - HTTPS_LOGE("header(int) not yet implemented"); + HTTPHeaders* headers = _activeRequest->getHTTPHeaders(); + auto allHeaders = headers->getAll(); + if (i >= 0 && i < allHeaders->size()) { + HTTPHeader* header = allHeaders->at(i); + return String(header->_value.c_str()); + } return ""; } String ESPWebServer::headerName(int i) { - // TODO - HTTPS_LOGE("headerName() not yet implemented"); + HTTPHeaders* headers = _activeRequest->getHTTPHeaders(); + auto allHeaders = headers->getAll(); + if (i >= 0 && i < allHeaders->size()) { + HTTPHeader* header = allHeaders->at(i); + return String(header->_name.c_str()); + } return ""; } int ESPWebServer::headers() { - // TODO - HTTPS_LOGE("headers() not yet implemented"); - return 0; + HTTPHeaders* headers = _activeRequest->getHTTPHeaders(); + auto allHeaders = headers->getAll(); + return allHeaders->size(); } bool ESPWebServer::hasHeader(String name) { - // TODO - HTTPS_LOGE("hasHeader() not yet implemented"); - return false; + HTTPHeaders* headers = _activeRequest->getHTTPHeaders(); + HTTPHeader* header = headers->get(std::string(name.c_str())); + return header != NULL; } String ESPWebServer::hostHeader() { - // TODO - HTTPS_LOGE("hostHeader() not yet implemented"); - return ""; + return header("Host"); } void ESPWebServer::send(int code, const char* content_type, const String& content) { @@ -285,9 +295,8 @@ void ESPWebServer::sendContent_P(PGM_P content, size_t size) { } String ESPWebServer::urlDecode(const String& text) { - // TODO - HTTPS_LOGE("urlDecode() not yet implemented"); - return text; + auto decoded = ::urlDecode(std::string(text.c_str())); + return String(decoded.c_str()); } void ESPWebServer::_handlerWrapper( From 9b65938a02c0d19459b92e21509d3341239c7394 Mon Sep 17 00:00:00 2001 From: Jack Jansen Date: Sun, 22 Dec 2019 00:02:24 +0100 Subject: [PATCH 13/54] Got rid of serveStatic() attempt: it's difficult, I don't need it and it isn't used in the standard WebServer examples --- src/ESPWebServer.cpp | 34 +--------------------------------- src/ESPWebServer.hpp | 21 --------------------- 2 files changed, 1 insertion(+), 54 deletions(-) diff --git a/src/ESPWebServer.cpp b/src/ESPWebServer.cpp index 8377133..ef298cb 100644 --- a/src/ESPWebServer.cpp +++ b/src/ESPWebServer.cpp @@ -94,9 +94,7 @@ void ESPWebServer::on(const String &uri, HTTPMethod method, THandlerFunction fn, } void ESPWebServer::serveStatic(const char* uri, fs::FS& fs, const char* path, const char* cache_header) { - // TODO: add * or something to path so serveStatic("/dir/",...) will serve all content from that directory - ESPWebServerStaticNode *node = new ESPWebServerStaticNode(this, std::string(path), fs, path, cache_header); - _server.registerNode(node); + HTTPS_LOGE("serveStatic() not implemented"); } void ESPWebServer::onNotFound(THandlerFunction fn) { @@ -328,33 +326,3 @@ ESPWebServerNode::ESPWebServerNode( ESPWebServerNode::~ESPWebServerNode() { } - -ESPWebServerStaticNode::ESPWebServerStaticNode( - ESPWebServer *server, - const std::string &path, - FS& fs, - const char *filePath, - const char *cache_header) -: ResourceNode(path, "GET", &(ESPWebServerStaticNode::_handlerWrapper), ""), - _fs(fs), - _filePath(filePath), - _cache_header(cache_header), - _isFile(false) -{ - _isFile = _fs.exists(filePath); -} - -void ESPWebServerStaticNode::_handler(httpsserver::HTTPRequest *req, httpsserver::HTTPResponse *res) { - HTTPS_LOGE("static not yet implemented path=%s filePath=%s\n", _path.c_str(), _filePath); -} - -void ESPWebServerStaticNode::_handlerWrapper(httpsserver::HTTPRequest *req, httpsserver::HTTPResponse *res) { - ESPWebServerStaticNode *node = (ESPWebServerStaticNode*)req->getResolvedNode(); - node->_handler(req, res); -} - - -ESPWebServerStaticNode::~ESPWebServerStaticNode() { - -} - diff --git a/src/ESPWebServer.hpp b/src/ESPWebServer.hpp index ccdbdba..ac92c0e 100644 --- a/src/ESPWebServer.hpp +++ b/src/ESPWebServer.hpp @@ -154,25 +154,4 @@ class ESPWebServerNode : public httpsserver::ResourceNode { const THandlerFunction _wrappedUploadHandler; }; -class ESPWebServerStaticNode : public httpsserver::ResourceNode { -public: - ESPWebServerStaticNode( - ESPWebServer *server, - const std::string &path, - FS& fs, - const char *filePath, - const char *cache_header); - virtual ~ESPWebServerStaticNode(); - -protected: - static void _handlerWrapper(httpsserver::HTTPRequest *req, httpsserver::HTTPResponse *res); - void _handler(httpsserver::HTTPRequest *req, httpsserver::HTTPResponse *res); - friend class ESPWebServer; - ESPWebServer *_wrapper; - FS& _fs; - const char *_filePath; - const char *_cache_header; - bool _isFile; -}; - #endif //ESPWEBSERVER_H \ No newline at end of file From 3eafa17ef018bb2172e3678c6f8df10e28fbb52c Mon Sep 17 00:00:00 2001 From: Jack Jansen Date: Sun, 22 Dec 2019 00:51:26 +0100 Subject: [PATCH 14/54] Debug prints for authentication --- src/ESPWebServer.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/ESPWebServer.cpp b/src/ESPWebServer.cpp index ef298cb..bbeac3d 100644 --- a/src/ESPWebServer.cpp +++ b/src/ESPWebServer.cpp @@ -55,12 +55,13 @@ void ESPWebServer::stop() { } bool ESPWebServer::authenticate(const char * username, const char * password) { - HTTPS_LOGE("authenticate() not yet implemented"); + HTTPS_LOGE("authenticate(%s, %s) not yet implemented", username, password); return false; } void ESPWebServer::requestAuthentication(HTTPAuthMethod mode, const char* realm, const String& authFailMsg) { if (realm == NULL) realm = "Login Required"; + HTTPS_LOGD("requestAuthentication(%s, %s)\n", mode, realm); if (mode == BASIC_AUTH) { std::string authArg = "Basic realm=\""; authArg += realm; From 727a8b850a7412bd800f629a126f58f1a652187f Mon Sep 17 00:00:00 2001 From: Jack Jansen Date: Sun, 22 Dec 2019 18:26:43 +0100 Subject: [PATCH 15/54] Implemented streamFile() --- src/ESPWebServer.cpp | 7 +++++++ src/ESPWebServer.hpp | 18 +++++++++++++++++- 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/src/ESPWebServer.cpp b/src/ESPWebServer.cpp index bbeac3d..461d3fd 100644 --- a/src/ESPWebServer.cpp +++ b/src/ESPWebServer.cpp @@ -222,6 +222,13 @@ String ESPWebServer::hostHeader() { return header("Host"); } +void ESPWebServer::_prepareStreamFile(size_t fileSize, const String& contentType) { + _contentLength = fileSize; + _activeResponse->setStatusCode(200); + _activeResponse->setHeader("Content-Type", contentType.c_str()); + _standardHeaders(); +} + void ESPWebServer::send(int code, const char* content_type, const String& content) { _contentLength = content.length(); _activeResponse->setStatusCode(code); diff --git a/src/ESPWebServer.hpp b/src/ESPWebServer.hpp index ac92c0e..110c57d 100644 --- a/src/ESPWebServer.hpp +++ b/src/ESPWebServer.hpp @@ -107,7 +107,20 @@ class ESPWebServer static String urlDecode(const String& text); - //template size_t streamFile(T &file, const String& contentType); + template size_t streamFile(T &file, const String& contentType) { + size_t fileSize = file.size(); + uint8_t buffer[HTTP_UPLOAD_BUFLEN]; + _prepareStreamFile(fileSize, contentType); + size_t didWrite = 0; + while (fileSize > 0) { + size_t thisRead = file.read(buffer, fileSize > HTTP_UPLOAD_BUFLEN ? HTTP_UPLOAD_BUFLEN : fileSize); + if (thisRead == 0) break; + _activeResponse->write(buffer, thisRead); + didWrite += thisRead; + fileSize -= thisRead; + } + return didWrite; + } protected: friend class ESPWebServerNode; @@ -118,6 +131,9 @@ class ESPWebServer /** Add standard headers */ void _standardHeaders(); + /** Prepare for streaming a file */ + void _prepareStreamFile(size_t fileSize, const String& contentType); + /** The backing server instance */ httpsserver::HTTPServer _server; From f09784b9885558536ed8e8b3678faa3e720eecfb Mon Sep 17 00:00:00 2001 From: Jack Jansen Date: Sun, 22 Dec 2019 22:49:57 +0100 Subject: [PATCH 16/54] Fixed issue with setting Content-Length incorrectly if it had been set previously with setContentLength() --- src/ESPWebServer.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/ESPWebServer.cpp b/src/ESPWebServer.cpp index 461d3fd..92530c5 100644 --- a/src/ESPWebServer.cpp +++ b/src/ESPWebServer.cpp @@ -230,7 +230,7 @@ void ESPWebServer::_prepareStreamFile(size_t fileSize, const String& contentType } void ESPWebServer::send(int code, const char* content_type, const String& content) { - _contentLength = content.length(); + if (_contentLength == CONTENT_LENGTH_NOT_SET) _contentLength = content.length(); _activeResponse->setStatusCode(code); _activeResponse->setHeader("Content-Type", content_type); _standardHeaders(); @@ -246,7 +246,7 @@ void ESPWebServer::send(int code, const String& content_type, const String& cont } void ESPWebServer::send_P(int code, PGM_P content_type, PGM_P content) { - _contentLength = strlen_P(content); + if (_contentLength == CONTENT_LENGTH_NOT_SET) _contentLength = strlen_P(content); _activeResponse->setStatusCode(code); String memContentType(FPSTR(content_type)); _activeResponse->setHeader("Content-Type", memContentType.c_str()); @@ -255,7 +255,7 @@ void ESPWebServer::send_P(int code, PGM_P content_type, PGM_P content) { } void ESPWebServer::send_P(int code, PGM_P content_type, PGM_P content, size_t contentLength) { - _contentLength = contentLength; + if (_contentLength == CONTENT_LENGTH_NOT_SET) _contentLength = contentLength; _activeResponse->setStatusCode(code); String memContentType(FPSTR(content_type)); _activeResponse->setHeader("Content-Type", memContentType.c_str()); From 4ef3d2bb34037fc6c30eb3f805610a86fad60d92 Mon Sep 17 00:00:00 2001 From: Jack Jansen Date: Mon, 23 Dec 2019 00:20:53 +0100 Subject: [PATCH 17/54] Getting started with WebServerSecure --- src/ESPWebServer.cpp | 25 ++++++++++++++++--------- src/ESPWebServer.hpp | 6 +++++- src/ESPWebServerSecure.cpp | 30 ++++++++++++++++++++++++++++++ src/ESPWebServerSecure.hpp | 34 ++++++++++++++++++++++++++++++++++ 4 files changed, 85 insertions(+), 10 deletions(-) create mode 100644 src/ESPWebServerSecure.cpp create mode 100644 src/ESPWebServerSecure.hpp diff --git a/src/ESPWebServer.cpp b/src/ESPWebServer.cpp index 92530c5..80237f9 100644 --- a/src/ESPWebServer.cpp +++ b/src/ESPWebServer.cpp @@ -20,15 +20,22 @@ struct { {HTTP_OPTIONS, "OPTIONS"}, }; +ESPWebServer::ESPWebServer(HTTPServer *server) : + _server(server), + _contentLength(0) +{ + _notFoundNode = nullptr; +} + ESPWebServer::ESPWebServer(IPAddress addr, int port) : - _server(HTTPServer(port, 4, addr)), + _server(new HTTPServer(port, 4, addr)), _contentLength(0) { _notFoundNode = nullptr; } ESPWebServer::ESPWebServer(int port) : - _server(HTTPServer(port, 4)) { + _server(new HTTPServer(port, 4)) { _notFoundNode = nullptr; } @@ -39,19 +46,19 @@ ESPWebServer::~ESPWebServer() { } void ESPWebServer::begin() { - _server.start(); + _server->start(); } void ESPWebServer::handleClient() { - _server.loop(); + _server->loop(); } void ESPWebServer::close() { - _server.stop(); + _server->stop(); } void ESPWebServer::stop() { - _server.stop(); + _server->stop(); } bool ESPWebServer::authenticate(const char * username, const char * password) { @@ -91,7 +98,7 @@ void ESPWebServer::on(const String &uri, HTTPMethod method, THandlerFunction fn, } } ESPWebServerNode *node = new ESPWebServerNode(this,std::string(uri.c_str()), std::string(methodname),fn, ufn); - _server.registerNode(node); + _server->registerNode(node); } void ESPWebServer::serveStatic(const char* uri, fs::FS& fs, const char* path, const char* cache_header) { @@ -103,7 +110,7 @@ void ESPWebServer::onNotFound(THandlerFunction fn) { delete _notFoundNode; } _notFoundNode = new ESPWebServerNode(this, "", "", fn, THandlerFunction()); - _server.setDefaultNode(_notFoundNode); + _server->setDefaultNode(_notFoundNode); } void ESPWebServer::onFileUpload(THandlerFunction fn) { @@ -270,7 +277,7 @@ void ESPWebServer::_standardHeaders() { } void ESPWebServer::enableCORS(boolean value) { - if (value) _server.setDefaultHeader("Access-Control-Allow-Origin", "*"); + if (value) _server->setDefaultHeader("Access-Control-Allow-Origin", "*"); } void ESPWebServer::enableCrossOrigin(boolean value) { diff --git a/src/ESPWebServer.hpp b/src/ESPWebServer.hpp index 110c57d..19e72e0 100644 --- a/src/ESPWebServer.hpp +++ b/src/ESPWebServer.hpp @@ -11,6 +11,7 @@ #include #include #include +#include #include "HTTP_Method.h" @@ -46,6 +47,9 @@ class ESPWebServerNode; class ESPWebServer { + friend class ESPWebServerSecure; +protected: + ESPWebServer(httpsserver::HTTPServer* _server); public: ESPWebServer(IPAddress addr, int port = 80); ESPWebServer(int port = 80); @@ -135,7 +139,7 @@ class ESPWebServer void _prepareStreamFile(size_t fileSize, const String& contentType); /** The backing server instance */ - httpsserver::HTTPServer _server; + httpsserver::HTTPServer* _server; /** The currently active request */ httpsserver::HTTPRequest *_activeRequest; diff --git a/src/ESPWebServerSecure.cpp b/src/ESPWebServerSecure.cpp new file mode 100644 index 0000000..04db490 --- /dev/null +++ b/src/ESPWebServerSecure.cpp @@ -0,0 +1,30 @@ +#include "ESPWebServerSecure.hpp" + + +ESPWebServerSecure::ESPWebServerSecure(IPAddress addr, int port) +: ESPWebServer(new httpsserver::HTTPSServer(&_sslCert, port, 4, addr)), + _underlyingServer(this), + _sslCert() +{} + +ESPWebServerSecure::ESPWebServerSecure(int port) +: ESPWebServer(new httpsserver::HTTPSServer(&_sslCert, port, 4)), + _underlyingServer(this), + _sslCert() +{} + +void ESPWebServerSecure::setServerKeyAndCert(const uint8_t *key, int keyLen, const uint8_t *cert, int certLen) { + _sslCert.setPK((unsigned char *)key, keyLen); + _sslCert.setCert((unsigned char *)cert, certLen); +} + +void ESPWebServerSecure::setServerKeyAndCert_P(const uint8_t *key, int keyLen, const uint8_t *cert, int certLen) { + setServerKeyAndCert(key, keyLen, cert, certLen); +} + +void ESPWebServerUnderlyingServer::setServerKeyAndCert(const uint8_t *key, int keyLen, const uint8_t *cert, int certLen) { + _webserver->setServerKeyAndCert(key, keyLen, cert, certLen); +} +void ESPWebServerUnderlyingServer::setServerKeyAndCert_P(const uint8_t *key, int keyLen, const uint8_t *cert, int certLen) { + _webserver->setServerKeyAndCert_P(key, keyLen, cert, certLen); +} diff --git a/src/ESPWebServerSecure.hpp b/src/ESPWebServerSecure.hpp new file mode 100644 index 0000000..ed32822 --- /dev/null +++ b/src/ESPWebServerSecure.hpp @@ -0,0 +1,34 @@ +#ifndef ESPWEBSERVERSECURE_H +#define ESPWEBSERVERSECURE_H + +#include "ESPWebServer.hpp" +#include +#include + +class ESPWebServerSecure; + +class ESPWebServerUnderlyingServer { + friend class ESPWebServerSecure; +protected: + ESPWebServerUnderlyingServer(ESPWebServerSecure *webserver) + : _webserver(webserver) + {} + ESPWebServerSecure* _webserver; +public: + void setServerKeyAndCert(const uint8_t *key, int keyLen, const uint8_t *cert, int certLen); + void setServerKeyAndCert_P(const uint8_t *key, int keyLen, const uint8_t *cert, int certLen); +}; + +class ESPWebServerSecure : public ESPWebServer { + friend class ESPWebServerUnderlyingServer; +public: + ESPWebServerSecure(IPAddress addr, int port = 442); + ESPWebServerSecure(int port = 442); + void setServerKeyAndCert(const uint8_t *key, int keyLen, const uint8_t *cert, int certLen); + void setServerKeyAndCert_P(const uint8_t *key, int keyLen, const uint8_t *cert, int certLen); +protected: + ESPWebServerUnderlyingServer _underlyingServer; + httpsserver::SSLCert _sslCert; +}; + +#endif //ESPWEBSERVERSECURE_H \ No newline at end of file From 32cdeabe2219eb5e3e4805071e37aac133831aa9 Mon Sep 17 00:00:00 2001 From: Jack Jansen Date: Sat, 8 Feb 2020 00:27:50 +0100 Subject: [PATCH 18/54] Added getServer() --- src/ESPWebServerSecure.hpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/ESPWebServerSecure.hpp b/src/ESPWebServerSecure.hpp index ed32822..6299c1a 100644 --- a/src/ESPWebServerSecure.hpp +++ b/src/ESPWebServerSecure.hpp @@ -7,6 +7,7 @@ class ESPWebServerSecure; +// Placeholder class, to make the API conform to what Esp8266WebServerSecure provides. class ESPWebServerUnderlyingServer { friend class ESPWebServerSecure; protected: @@ -26,6 +27,7 @@ class ESPWebServerSecure : public ESPWebServer { ESPWebServerSecure(int port = 442); void setServerKeyAndCert(const uint8_t *key, int keyLen, const uint8_t *cert, int certLen); void setServerKeyAndCert_P(const uint8_t *key, int keyLen, const uint8_t *cert, int certLen); + ESPWebServerUnderlyingServer& getServer() { return _underlyingServer; } protected: ESPWebServerUnderlyingServer _underlyingServer; httpsserver::SSLCert _sslCert; From 4e3abe8a7e3ff4df519e2bd011467b3baee64b79 Mon Sep 17 00:00:00 2001 From: Jack Jansen Date: Sat, 8 Feb 2020 20:55:53 +0100 Subject: [PATCH 19/54] Implemented get("plain") returning BODY. Closes #2. --- src/ESPWebServer.cpp | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/src/ESPWebServer.cpp b/src/ESPWebServer.cpp index 80237f9..fde50e8 100644 --- a/src/ESPWebServer.cpp +++ b/src/ESPWebServer.cpp @@ -141,6 +141,29 @@ String ESPWebServer::pathArg(unsigned int i) { } String ESPWebServer::arg(String name) { + // Special case: arg("plain") returns the body of non-multipart requests. + if (name == "plain") { + bool isForm = false; + HTTPHeaders* headers = _activeRequest->getHTTPHeaders(); + HTTPHeader* ctHeader = headers->get("Content-Type"); + if (ctHeader && ctHeader->_value.substr(0, 10) == "multipart/") { + isForm = true; + } + if (!isForm) { + size_t bodyLength = _activeRequest->getContentLength(); + String rv; + rv.reserve(bodyLength); + char buffer[257]; + while(!_activeRequest->requestComplete()) { + size_t readLength = _activeRequest->readBytes((byte*)buffer, 256); + if (readLength <= 0) break; + buffer[readLength] = 0; + rv += buffer; + } + HTTPS_LOGD("arg(\"plain\") returns %d bytes", rv.length()); + return rv; + } + } ResourceParameters *params = _activeRequest->getParams(); std::string value; params->getQueryParameter(std::string(name.c_str()), value); From 5abd395abe5a6cfcd06c29c7daecdff856977e80 Mon Sep 17 00:00:00 2001 From: Jack Jansen Date: Sat, 8 Feb 2020 21:50:49 +0100 Subject: [PATCH 20/54] Attempting to add form test --- examples/HelloServer/HelloServer.ino | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/examples/HelloServer/HelloServer.ino b/examples/HelloServer/HelloServer.ino index 0388358..bbe80ec 100644 --- a/examples/HelloServer/HelloServer.ino +++ b/examples/HelloServer/HelloServer.ino @@ -16,6 +16,21 @@ void handleRoot() { digitalWrite(led, 0); } +void handleForm() { + String line = server.get("line"); + String multi = server.get("multi"); + line = line.toLowerCase() + line.toUpperCase(); + multi = multi.toLowerCase() + multi.toUpperCase(); + String rv; + rv = "Test Form"; + rv += "
"; + rv += "Single line:

"; + rv += "Multi line:

"; + rv += ""; + rv += "
"; + return rv; +} + void handleNotFound() { digitalWrite(led, 1); String message = "File Not Found\n\n"; From eddc67e6ca4c7f091d2e2032132f1b5e76c2949d Mon Sep 17 00:00:00 2001 From: Jack Jansen Date: Sat, 8 Feb 2020 21:58:58 +0100 Subject: [PATCH 21/54] Fixed example to be buildable with platformio --- examples/HelloServer/HelloServer.ino | 85 +--------------------- examples/HelloServer/mainHelloServer.cpp | 89 ++++++++++++++++++++++++ 2 files changed, 90 insertions(+), 84 deletions(-) create mode 100644 examples/HelloServer/mainHelloServer.cpp diff --git a/examples/HelloServer/HelloServer.ino b/examples/HelloServer/HelloServer.ino index bbe80ec..092a065 100644 --- a/examples/HelloServer/HelloServer.ino +++ b/examples/HelloServer/HelloServer.ino @@ -1,88 +1,5 @@ #include #include -#include +#include #include -const char* ssid = "........"; -const char* password = "........"; - -ESPWebServer server(80); - -const int led = 13; - -void handleRoot() { - digitalWrite(led, 1); - server.send(200, "text/plain", "hello from esp32!"); - digitalWrite(led, 0); -} - -void handleForm() { - String line = server.get("line"); - String multi = server.get("multi"); - line = line.toLowerCase() + line.toUpperCase(); - multi = multi.toLowerCase() + multi.toUpperCase(); - String rv; - rv = "Test Form"; - rv += "
"; - rv += "Single line:

"; - rv += "Multi line:

"; - rv += ""; - rv += "
"; - return rv; -} - -void handleNotFound() { - digitalWrite(led, 1); - String message = "File Not Found\n\n"; - message += "URI: "; - message += server.uri(); - message += "\nMethod: "; - message += (server.method() == HTTP_GET) ? "GET" : "POST"; - message += "\nArguments: "; - message += server.args(); - message += "\n"; - for (uint8_t i = 0; i < server.args(); i++) { - message += " " + server.argName(i) + ": " + server.arg(i) + "\n"; - } - server.send(404, "text/plain", message); - digitalWrite(led, 0); -} - -void setup(void) { - pinMode(led, OUTPUT); - digitalWrite(led, 0); - Serial.begin(115200); - WiFi.mode(WIFI_STA); - WiFi.begin(ssid, password); - Serial.println(""); - - // Wait for connection - while (WiFi.status() != WL_CONNECTED) { - delay(500); - Serial.print("."); - } - Serial.println(""); - Serial.print("Connected to "); - Serial.println(ssid); - Serial.print("IP address: "); - Serial.println(WiFi.localIP()); - - if (MDNS.begin("esp32")) { - Serial.println("MDNS responder started"); - } - - server.on("/", handleRoot); - - server.on("/inline", []() { - server.send(200, "text/plain", "this works as well"); - }); - - server.onNotFound(handleNotFound); - - server.begin(); - Serial.println("HTTP server started"); -} - -void loop(void) { - server.handleClient(); -} diff --git a/examples/HelloServer/mainHelloServer.cpp b/examples/HelloServer/mainHelloServer.cpp new file mode 100644 index 0000000..40fe180 --- /dev/null +++ b/examples/HelloServer/mainHelloServer.cpp @@ -0,0 +1,89 @@ +#include +#include +#include +#include +#include + +const char* ssid = "........"; +const char* password = "........"; + +ESPWebServer server(80); + +const int led = 13; + +void handleRoot() { + digitalWrite(led, 1); + server.send(200, "text/plain", "hello from esp32!"); + digitalWrite(led, 0); +} + +void handleForm() { + String line = server.arg("line"); + String multi = server.arg("multi"); + line.toLowerCase(); + multi.toUpperCase(); + String rv; + rv = "Test Form"; + rv += "
"; + rv += "Single line:

"; + rv += "Multi line:

"; + rv += ""; + rv += "
"; + server.send(200, "text/html", rv); +} + +void handleNotFound() { + digitalWrite(led, 1); + String message = "File Not Found\n\n"; + message += "URI: "; + message += server.uri(); + message += "\nMethod: "; + message += (server.method() == HTTP_GET) ? "GET" : "POST"; + message += "\nArguments: "; + message += server.args(); + message += "\n"; + for (uint8_t i = 0; i < server.args(); i++) { + message += " " + server.argName(i) + ": " + server.arg(i) + "\n"; + } + server.send(404, "text/plain", message); + digitalWrite(led, 0); +} + +void setup(void) { + pinMode(led, OUTPUT); + digitalWrite(led, 0); + Serial.begin(115200); + WiFi.mode(WIFI_STA); + WiFi.begin(ssid, password); + Serial.println(""); + + // Wait for connection + while (WiFi.status() != WL_CONNECTED) { + delay(500); + Serial.print("."); + } + Serial.println(""); + Serial.print("Connected to "); + Serial.println(ssid); + Serial.print("IP address: "); + Serial.println(WiFi.localIP()); + + if (MDNS.begin("esp32")) { + Serial.println("MDNS responder started"); + } + + server.on("/", handleRoot); + + server.on("/inline", []() { + server.send(200, "text/plain", "this works as well"); + }); + + server.onNotFound(handleNotFound); + + server.begin(); + Serial.println("HTTP server started"); +} + +void loop(void) { + server.handleClient(); +} From 58daa74be9e74dd0e8843608d1a48ecf3772a099 Mon Sep 17 00:00:00 2001 From: Jack Jansen Date: Sat, 8 Feb 2020 23:12:24 +0100 Subject: [PATCH 22/54] Added /form to the server --- examples/HelloServer/mainHelloServer.cpp | 14 +++++++++----- platformio.ini | 1 + src/ESPWebServer.cpp | 2 +- 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/examples/HelloServer/mainHelloServer.cpp b/examples/HelloServer/mainHelloServer.cpp index 40fe180..5d9ac98 100644 --- a/examples/HelloServer/mainHelloServer.cpp +++ b/examples/HelloServer/mainHelloServer.cpp @@ -4,8 +4,8 @@ #include #include -const char* ssid = "........"; -const char* password = "........"; +const char* ssid = "......"; +const char* password = "......"; ESPWebServer server(80); @@ -13,13 +13,17 @@ const int led = 13; void handleRoot() { digitalWrite(led, 1); - server.send(200, "text/plain", "hello from esp32!"); + server.send(200, "text/plain", "hello from esp32! See /form and /inline too!"); digitalWrite(led, 0); } void handleForm() { String line = server.arg("line"); + Serial.print("line: "); + Serial.println(line); String multi = server.arg("multi"); + Serial.print("multi: "); + Serial.println(multi); line.toLowerCase(); multi.toUpperCase(); String rv; @@ -52,7 +56,7 @@ void handleNotFound() { void setup(void) { pinMode(led, OUTPUT); digitalWrite(led, 0); - Serial.begin(115200); + Serial.begin(9600); WiFi.mode(WIFI_STA); WiFi.begin(ssid, password); Serial.println(""); @@ -73,7 +77,7 @@ void setup(void) { } server.on("/", handleRoot); - + server.on("/form", handleForm); server.on("/inline", []() { server.send(200, "text/plain", "this works as well"); }); diff --git a/platformio.ini b/platformio.ini index 504f2b1..d6bbe83 100644 --- a/platformio.ini +++ b/platformio.ini @@ -7,4 +7,5 @@ platform = espressif32@>=1.11 board = lolin32 lib_ldf_mode = deep+ lib_deps = https://github.com/jackjansen/esp32_https_server.git#exp-jack-compat +build_flags = -DHTTPS_LOGLEVEL=4 -DHTTPS_REQUEST_MAX_REQUEST_LENGTH=800 src_filter = +<*> +<../examples/HelloServer> diff --git a/src/ESPWebServer.cpp b/src/ESPWebServer.cpp index fde50e8..b0a8d9a 100644 --- a/src/ESPWebServer.cpp +++ b/src/ESPWebServer.cpp @@ -68,7 +68,7 @@ bool ESPWebServer::authenticate(const char * username, const char * password) { void ESPWebServer::requestAuthentication(HTTPAuthMethod mode, const char* realm, const String& authFailMsg) { if (realm == NULL) realm = "Login Required"; - HTTPS_LOGD("requestAuthentication(%s, %s)\n", mode, realm); + HTTPS_LOGD("requestAuthentication(%d, %s)\n", mode, realm); if (mode == BASIC_AUTH) { std::string authArg = "Basic realm=\""; authArg += realm; From 5a696b4849f373b3bc3dda3e889084f17ed82f2a Mon Sep 17 00:00:00 2001 From: Jack Jansen Date: Wed, 4 Mar 2020 17:45:25 +0100 Subject: [PATCH 23/54] Allow NULL parameters for send() strings --- src/ESPWebServer.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/ESPWebServer.cpp b/src/ESPWebServer.cpp index b0a8d9a..d84a561 100644 --- a/src/ESPWebServer.cpp +++ b/src/ESPWebServer.cpp @@ -262,9 +262,13 @@ void ESPWebServer::_prepareStreamFile(size_t fileSize, const String& contentType void ESPWebServer::send(int code, const char* content_type, const String& content) { if (_contentLength == CONTENT_LENGTH_NOT_SET) _contentLength = content.length(); _activeResponse->setStatusCode(code); - _activeResponse->setHeader("Content-Type", content_type); + if (content_type != NULL) { + _activeResponse->setHeader("Content-Type", content_type); + } _standardHeaders(); - _activeResponse->print(content); + if (content) { + _activeResponse->print(content); + } } void ESPWebServer::send(int code, char* content_type, const String& content) { From 92bfe6029d4c9b66f2b15debeb9085b189c49409 Mon Sep 17 00:00:00 2001 From: Jack Jansen Date: Wed, 4 Mar 2020 17:47:01 +0100 Subject: [PATCH 24/54] Modifying example for POST forms --- examples/HelloServer/mainHelloServer.cpp | 62 ++++++++++++++++++++++-- platformio.ini | 4 +- 2 files changed, 61 insertions(+), 5 deletions(-) diff --git a/examples/HelloServer/mainHelloServer.cpp b/examples/HelloServer/mainHelloServer.cpp index 5d9ac98..c3affa0 100644 --- a/examples/HelloServer/mainHelloServer.cpp +++ b/examples/HelloServer/mainHelloServer.cpp @@ -4,8 +4,8 @@ #include #include -const char* ssid = "......"; -const char* password = "......"; +const char* ssid = "........"; +const char* password = "........"; ESPWebServer server(80); @@ -28,7 +28,20 @@ void handleForm() { multi.toUpperCase(); String rv; rv = "Test Form"; - rv += "
"; + rv += "

Form using GET

"; + rv += ""; + rv += "Single line:

"; + rv += "Multi line:

"; + rv += ""; + rv += "
"; + rv += "

Form using POST urlencoded

"; + rv += "
"; + rv += "Single line:

"; + rv += "Multi line:

"; + rv += ""; + rv += "
"; + rv += "

Form using POST with multipart

"; + rv += "
"; rv += "Single line:

"; rv += "Multi line:

"; rv += ""; @@ -36,6 +49,45 @@ void handleForm() { server.send(200, "text/html", rv); } +void handleUpload() { + Serial.println("handleUpload() called"); + server.send(200); +} + +void handleUploadFile() { + Serial.println("handleUploadFile() called"); + HTTPUpload& upload = server.upload(); + if(upload.status == UPLOAD_FILE_START){ + String filename = upload.filename; + Serial.printf("upload filename=%s\n", filename.c_str()); +#if 0 + if(!filename.startsWith("/")) filename = "/"+filename; + Serial.print("handleFileUpload Name: "); Serial.println(filename); + fsUploadFile = SPIFFS.open(filename, "w"); // Open the file for writing in SPIFFS (create if it doesn't exist) + filename = String(); +#endif + } else if(upload.status == UPLOAD_FILE_WRITE){ + Serial.printf("uploaded %d bytes\n", upload.currentSize); +#if 0 + if(fsUploadFile) + fsUploadFile.write(upload.buf, upload.currentSize); // Write the received bytes to the file +#endif + } else if(upload.status == UPLOAD_FILE_END){ + Serial.printf("upload total %d bytes\n", upload.totalSize); +#if 0 + if(fsUploadFile) { // If the file was successfully created + fsUploadFile.close(); // Close the file again + Serial.print("handleFileUpload Size: "); Serial.println(upload.totalSize); + server.sendHeader("Location","/success.html"); // Redirect the client to the success page + server.send(303); + } else { + server.send(500, "text/plain", "500: couldn't create file"); + } +#endif + server.send(200, "text/plain", "OK"); + } +} + void handleNotFound() { digitalWrite(led, 1); String message = "File Not Found\n\n"; @@ -56,7 +108,7 @@ void handleNotFound() { void setup(void) { pinMode(led, OUTPUT); digitalWrite(led, 0); - Serial.begin(9600); + Serial.begin(115200); WiFi.mode(WIFI_STA); WiFi.begin(ssid, password); Serial.println(""); @@ -78,6 +130,8 @@ void setup(void) { server.on("/", handleRoot); server.on("/form", handleForm); + server.on("/form", HTTP_POST, handleForm); + server.on("/upload", HTTP_POST, handleUpload, handleUploadFile); server.on("/inline", []() { server.send(200, "text/plain", "this works as well"); }); diff --git a/platformio.ini b/platformio.ini index d6bbe83..1b3f69e 100644 --- a/platformio.ini +++ b/platformio.ini @@ -6,6 +6,8 @@ framework = arduino platform = espressif32@>=1.11 board = lolin32 lib_ldf_mode = deep+ -lib_deps = https://github.com/jackjansen/esp32_https_server.git#exp-jack-compat +lib_deps = https://github.com/jackjansen/esp32_https_server.git#bodyparser build_flags = -DHTTPS_LOGLEVEL=4 -DHTTPS_REQUEST_MAX_REQUEST_LENGTH=800 src_filter = +<*> +<../examples/HelloServer> +monitor_speed = 115200 +upload_speed = 115200 \ No newline at end of file From 1476fdc927d452ef362ebcfb6d3b5b1a66684f31 Mon Sep 17 00:00:00 2001 From: Jack Jansen Date: Sat, 7 Mar 2020 21:10:48 +0100 Subject: [PATCH 25/54] Started implementing post --- examples/HelloServer/HelloServer.ino | 7 ++- examples/HelloServer/mainHelloServer.cpp | 19 ++++++- src/ESPWebServer.cpp | 63 ++++++++++++++++++++++++ 3 files changed, 86 insertions(+), 3 deletions(-) diff --git a/examples/HelloServer/HelloServer.ino b/examples/HelloServer/HelloServer.ino index 092a065..780e426 100644 --- a/examples/HelloServer/HelloServer.ino +++ b/examples/HelloServer/HelloServer.ino @@ -1,5 +1,8 @@ #include #include -#include #include - +#if 0 +#include +#else +#include +#endif diff --git a/examples/HelloServer/mainHelloServer.cpp b/examples/HelloServer/mainHelloServer.cpp index c3affa0..ef75039 100644 --- a/examples/HelloServer/mainHelloServer.cpp +++ b/examples/HelloServer/mainHelloServer.cpp @@ -1,8 +1,13 @@ #include #include #include -#include #include +#if 0 +#include +typedef WebServer ESPWebServer; +#else +#include +#endif const char* ssid = "........"; const char* password = "........"; @@ -24,6 +29,9 @@ void handleForm() { String multi = server.arg("multi"); Serial.print("multi: "); Serial.println(multi); + String file = server.arg("file"); + Serial.print("file: "); + Serial.println(file); line.toLowerCase(); multi.toUpperCase(); String rv; @@ -32,18 +40,21 @@ void handleForm() { rv += ""; rv += "Single line:

"; rv += "Multi line:

"; + rv += "File:

"; rv += ""; rv += ""; rv += "

Form using POST urlencoded

"; rv += "
"; rv += "Single line:

"; rv += "Multi line:

"; + rv += "File:

"; rv += ""; rv += "
"; rv += "

Form using POST with multipart

"; rv += "
"; rv += "Single line:

"; rv += "Multi line:

"; + rv += "File:

"; rv += ""; rv += "
"; server.send(200, "text/html", rv); @@ -51,6 +62,12 @@ void handleForm() { void handleUpload() { Serial.println("handleUpload() called"); + String line = server.arg("line"); + Serial.print("line: "); + Serial.println(line); + String multi = server.arg("multi"); + Serial.print("multi: "); + Serial.println(multi); server.send(200); } diff --git a/src/ESPWebServer.cpp b/src/ESPWebServer.cpp index d84a561..4e517dc 100644 --- a/src/ESPWebServer.cpp +++ b/src/ESPWebServer.cpp @@ -1,12 +1,19 @@ #include "ESPWebServer.hpp" +#include +#include #include +#include using namespace httpsserver; /* Copy the content of Arduino String s into a newly allocated char array p */ #define ARDUINOTONEWCHARARR(s,p) {size_t sLen=s.length()+1;char *c=new char[sLen];c[sLen-1]=0;s.toCharArray(p,sLen);p=c;} +class BodyResourceParameters : public ResourceParameters { + friend class ESPWebServer; +}; + struct { int val; char text[8]; @@ -346,6 +353,62 @@ void ESPWebServer::_handlerWrapper( node->_wrapper->_activeRequest = req; node->_wrapper->_activeResponse = res; node->_wrapper->_contentLength = CONTENT_LENGTH_NOT_SET; + // POST form data needs to be handled specially + if (req->getMethod() == "POST") { + HTTPBodyParser *parser = NULL; + std::string contentType = req->getHeader("Content-Type"); + size_t semicolonPos = contentType.find(";"); + if (semicolonPos != std::string::npos) { + contentType = contentType.substr(0, semicolonPos); + } + if (contentType == "multipart/form-data") { + parser = new HTTPMultipartBodyParser(req); + } + if (contentType == "application/x-www-form-urlencoded") { + parser = new HTTPMultipartBodyParser(req); + } + BodyResourceParameters bodyFields; + + while (parser && parser->nextField()) { + std::string name = parser->getFieldName(); + std::string filename = parser->getFieldFilename(); + if (filename != "") { + // This field is a file. Use the uploader + std::string mimeType = parser->getFieldMimeType(); + HTTPUpload uploader; + node->_wrapper->_activeUpload = &uploader; + uploader.status = UPLOAD_FILE_START; + uploader.name = String(name.c_str()); + uploader.filename = String(filename.c_str()); + uploader.type = String(mimeType.c_str()); + uploader.totalSize = 0; + uploader.currentSize = 0; + // First call to the uploader callback + node->_wrappedUploadHandler(); + // Now loop over the data + uploader.status = UPLOAD_FILE_WRITE; + while(!parser->endOfField()) { + uploader.currentSize = parser->read(uploader.buf, sizeof(uploader.buf)); + uploader.totalSize += uploader.currentSize; + node->_wrappedUploadHandler(); + } + uploader.status = UPLOAD_FILE_END; + node->_wrappedUploadHandler(); + node->_wrapper->_activeUpload = NULL; + } else { + // This field is not a file. Add the value + std::string value(""); + while (!parser->endOfField()) { + byte buf[512]; + size_t readLength = parser->read(buf, 512); + std::string bufString((char *)buf, readLength); + value += bufString; + } + bodyFields.setQueryParameter(name, value); + } + } + delete parser; + } node->_wrappedHandler(); node->_wrapper->_activeRequest = nullptr; node->_wrapper->_activeResponse = nullptr; From 669f7c77c1d4321039bf01eeacc8258ae894893b Mon Sep 17 00:00:00 2001 From: Jack Jansen Date: Sat, 7 Mar 2020 21:12:30 +0100 Subject: [PATCH 26/54] Adding .pio --- .gitignore | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 600d2d3..42f8df3 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ -.vscode \ No newline at end of file +.vscode +.pio \ No newline at end of file From 8a5ef9203177e1170f713e13eccd573d7fefbe95 Mon Sep 17 00:00:00 2001 From: Jack Jansen Date: Sat, 7 Mar 2020 21:51:19 +0100 Subject: [PATCH 27/54] Example fileserver copied from exp32_https_server and adapted. Untested. --- examples/FormServer/FormServer.ino | 199 +++++++++++++++++++++++++++++ 1 file changed, 199 insertions(+) create mode 100644 examples/FormServer/FormServer.ino diff --git a/examples/FormServer/FormServer.ino b/examples/FormServer/FormServer.ino new file mode 100644 index 0000000..3e184e6 --- /dev/null +++ b/examples/FormServer/FormServer.ino @@ -0,0 +1,199 @@ +#include +#include +#include +#include +#if 0 +#include +typedef WebServer ESPWebServer; +#else +#include +#endif + +const char* ssid = "........"; +const char* password = "........"; + +ESPWebServer server(80); + +void handleRoot() { + String rv; + rv += ""; + rv += ""; + rv += "Very simple file server"; + rv += ""; + rv += "

Very simple file server

"; + rv += "

This is a very simple file server to demonstrate the use of POST forms.

"; + rv += "

List existing files

"; + rv += "

See /public to list existing files and retrieve or edit them.

"; + rv += "

Upload new file

"; + rv += "

This form allows you to upload files (text, jpg and png supported best). It demonstrates multipart/form-data.

"; + rv += "
"; + rv += "file:
"; + rv += ""; + rv += "
"; + rv += ""; + rv += ""; + server.send(200, "text/html", rv); +} + +void handleFormEdit() { + String filename = server.arg("filename"); + String pathname = String("/public/") + filename; + String rv; + rv += "Edit File\n"; + File file = SPIFFS.open(pathname.c_str()); + if (!hasFilename) { + rv += "

No filename specified.

\n"; + } else if (!file.available()) { + rv += "

File not found:"; + rv += pathname; + rv += "

\n"; + } else { + rv += "

Edit content of "; + rv += pathname; + rv += "

\n"; + rv += "
\n"; + rv += "\n"; + rv += "
"; + rv += ""; + rv += "
"; + } + rv += ""; + server.send(200, "text/html", rv); +} + +void handleFormUpload() { + Serial.println("handleUpload() called"); + server.send(200); +} + +void handleFormUploadFile() { + Serial.println("handleUploadFile() called"); + HTTPUpload& upload = server.upload(); + if(upload.status == UPLOAD_FILE_START){ + String filename = String("/public/") + upload.filename; + Serial.printf("upload filename=%s\n", filename.c_str()); + Serial.print("handleFileUpload Name: "); Serial.println(filename); + fsUploadFile = SPIFFS.open(filename, "w"); // Open the file for writing in SPIFFS (create if it doesn't exist) + } else if(upload.status == UPLOAD_FILE_WRITE){ + Serial.printf("uploaded %d bytes\n", upload.currentSize); + if(fsUploadFile) + fsUploadFile.write(upload.buf, upload.currentSize); // Write the received bytes to the file + } else if(upload.status == UPLOAD_FILE_END){ + Serial.printf("upload total %d bytes\n", upload.totalSize); + if(fsUploadFile) { // If the file was successfully created + fsUploadFile.close(); // Close the file again + Serial.print("handleFileUpload Size: "); Serial.println(upload.totalSize); + server.sendHeader("Location","/public"); // Redirect the client to the success page + server.send(303); + } else { + server.send(500, "text/plain", "500: couldn't create file"); + } + server.send(200, "text/plain", "OK"); + } +} + +void handleDirectory() { + if (server.hasArg("filename")) { + // Download file + return; + } + String rv; + rv += "File Listing\n"; + File d = SPIFFS.open("/public"); + if (!d.isDirectory()) { + rv += "

No files found.

\n"; + } else { + rv += "

File Listing

\n"; + rv += "
    \n"; + File f = d.openNextFile(); + while (f) { + std::string pathname(f.name()); + std::string filename = pathname.substr(8); // Remove /public/ + rv += "
  • "; + rv += String(filename.c_str()); + rv += ""; + if (pathname.rfind(".txt") != std::string::npos) { + rv += " [edit]"; + } + rv += "
  • "; + f = d.openNextFile(); + } + rv += "
"; + } + rv += ""; + server.send(200, "text/html", rv); +} + +void handleNotFound() { + digitalWrite(led, 1); + String message = "File Not Found\n\n"; + message += "URI: "; + message += server.uri(); + message += "\nMethod: "; + message += (server.method() == HTTP_GET) ? "GET" : "POST"; + message += "\nArguments: "; + message += server.args(); + message += "\n"; + for (uint8_t i = 0; i < server.args(); i++) { + message += " " + server.argName(i) + ": " + server.arg(i) + "\n"; + } + server.send(404, "text/plain", message); + digitalWrite(led, 0); +} + +void setup(void) { + pinMode(led, OUTPUT); + digitalWrite(led, 0); + Serial.begin(115200); + WiFi.mode(WIFI_STA); + WiFi.begin(ssid, password); + Serial.println(""); + + // Wait for connection + while (WiFi.status() != WL_CONNECTED) { + delay(500); + Serial.print("."); + } + Serial.println(""); + Serial.print("Connected to "); + Serial.println(ssid); + Serial.print("IP address: "); + Serial.println(WiFi.localIP()); + + if (MDNS.begin("esp32")) { + Serial.println("MDNS responder started"); + } + // Setup filesystem + if (!SPIFFS.begin(true)) Serial.println("Mounting SPIFFS failed"); + + server.on("/", handleRoot); + server.on("/upload", HTTP_POST, handleFormUpload, handleFormUploadFile); + server.on("/edit", HTTP_GET, handleFormEdit); + server.on("/edit", HTTP_POST, handleFormEdit); + server.on("/public", HTTP_GET, handleDirectory); + + server.onNotFound(handleNotFound); + + server.begin(); + Serial.println("HTTP server started"); +} + +void loop(void) { + server.handleClient(); +} From e24192b5904273e252ea65d65fdb1a9c5f79d843 Mon Sep 17 00:00:00 2001 From: Jack Jansen Date: Sun, 8 Mar 2020 20:35:00 +0100 Subject: [PATCH 28/54] Adapted FormServer example to work with normal webserver too --- examples/FormServer/FormServer.ino | 191 +------------------ examples/FormServer/mainFormServer.cpp | 248 +++++++++++++++++++++++++ platformio.ini | 2 +- 3 files changed, 250 insertions(+), 191 deletions(-) create mode 100644 examples/FormServer/mainFormServer.cpp diff --git a/examples/FormServer/FormServer.ino b/examples/FormServer/FormServer.ino index 3e184e6..fd50093 100644 --- a/examples/FormServer/FormServer.ino +++ b/examples/FormServer/FormServer.ino @@ -2,198 +2,9 @@ #include #include #include +#include #if 0 #include -typedef WebServer ESPWebServer; #else #include #endif - -const char* ssid = "........"; -const char* password = "........"; - -ESPWebServer server(80); - -void handleRoot() { - String rv; - rv += ""; - rv += ""; - rv += "Very simple file server"; - rv += ""; - rv += "

Very simple file server

"; - rv += "

This is a very simple file server to demonstrate the use of POST forms.

"; - rv += "

List existing files

"; - rv += "

See /public to list existing files and retrieve or edit them.

"; - rv += "

Upload new file

"; - rv += "

This form allows you to upload files (text, jpg and png supported best). It demonstrates multipart/form-data.

"; - rv += "
"; - rv += "file:
"; - rv += ""; - rv += "
"; - rv += ""; - rv += ""; - server.send(200, "text/html", rv); -} - -void handleFormEdit() { - String filename = server.arg("filename"); - String pathname = String("/public/") + filename; - String rv; - rv += "Edit File\n"; - File file = SPIFFS.open(pathname.c_str()); - if (!hasFilename) { - rv += "

No filename specified.

\n"; - } else if (!file.available()) { - rv += "

File not found:"; - rv += pathname; - rv += "

\n"; - } else { - rv += "

Edit content of "; - rv += pathname; - rv += "

\n"; - rv += "
\n"; - rv += "\n"; - rv += "
"; - rv += ""; - rv += "
"; - } - rv += ""; - server.send(200, "text/html", rv); -} - -void handleFormUpload() { - Serial.println("handleUpload() called"); - server.send(200); -} - -void handleFormUploadFile() { - Serial.println("handleUploadFile() called"); - HTTPUpload& upload = server.upload(); - if(upload.status == UPLOAD_FILE_START){ - String filename = String("/public/") + upload.filename; - Serial.printf("upload filename=%s\n", filename.c_str()); - Serial.print("handleFileUpload Name: "); Serial.println(filename); - fsUploadFile = SPIFFS.open(filename, "w"); // Open the file for writing in SPIFFS (create if it doesn't exist) - } else if(upload.status == UPLOAD_FILE_WRITE){ - Serial.printf("uploaded %d bytes\n", upload.currentSize); - if(fsUploadFile) - fsUploadFile.write(upload.buf, upload.currentSize); // Write the received bytes to the file - } else if(upload.status == UPLOAD_FILE_END){ - Serial.printf("upload total %d bytes\n", upload.totalSize); - if(fsUploadFile) { // If the file was successfully created - fsUploadFile.close(); // Close the file again - Serial.print("handleFileUpload Size: "); Serial.println(upload.totalSize); - server.sendHeader("Location","/public"); // Redirect the client to the success page - server.send(303); - } else { - server.send(500, "text/plain", "500: couldn't create file"); - } - server.send(200, "text/plain", "OK"); - } -} - -void handleDirectory() { - if (server.hasArg("filename")) { - // Download file - return; - } - String rv; - rv += "File Listing\n"; - File d = SPIFFS.open("/public"); - if (!d.isDirectory()) { - rv += "

No files found.

\n"; - } else { - rv += "

File Listing

\n"; - rv += "
    \n"; - File f = d.openNextFile(); - while (f) { - std::string pathname(f.name()); - std::string filename = pathname.substr(8); // Remove /public/ - rv += "
  • "; - rv += String(filename.c_str()); - rv += ""; - if (pathname.rfind(".txt") != std::string::npos) { - rv += " [edit]"; - } - rv += "
  • "; - f = d.openNextFile(); - } - rv += "
"; - } - rv += ""; - server.send(200, "text/html", rv); -} - -void handleNotFound() { - digitalWrite(led, 1); - String message = "File Not Found\n\n"; - message += "URI: "; - message += server.uri(); - message += "\nMethod: "; - message += (server.method() == HTTP_GET) ? "GET" : "POST"; - message += "\nArguments: "; - message += server.args(); - message += "\n"; - for (uint8_t i = 0; i < server.args(); i++) { - message += " " + server.argName(i) + ": " + server.arg(i) + "\n"; - } - server.send(404, "text/plain", message); - digitalWrite(led, 0); -} - -void setup(void) { - pinMode(led, OUTPUT); - digitalWrite(led, 0); - Serial.begin(115200); - WiFi.mode(WIFI_STA); - WiFi.begin(ssid, password); - Serial.println(""); - - // Wait for connection - while (WiFi.status() != WL_CONNECTED) { - delay(500); - Serial.print("."); - } - Serial.println(""); - Serial.print("Connected to "); - Serial.println(ssid); - Serial.print("IP address: "); - Serial.println(WiFi.localIP()); - - if (MDNS.begin("esp32")) { - Serial.println("MDNS responder started"); - } - // Setup filesystem - if (!SPIFFS.begin(true)) Serial.println("Mounting SPIFFS failed"); - - server.on("/", handleRoot); - server.on("/upload", HTTP_POST, handleFormUpload, handleFormUploadFile); - server.on("/edit", HTTP_GET, handleFormEdit); - server.on("/edit", HTTP_POST, handleFormEdit); - server.on("/public", HTTP_GET, handleDirectory); - - server.onNotFound(handleNotFound); - - server.begin(); - Serial.println("HTTP server started"); -} - -void loop(void) { - server.handleClient(); -} diff --git a/examples/FormServer/mainFormServer.cpp b/examples/FormServer/mainFormServer.cpp new file mode 100644 index 0000000..3fa0383 --- /dev/null +++ b/examples/FormServer/mainFormServer.cpp @@ -0,0 +1,248 @@ +#include +#include +#include +#include +#include +#if 0 +#include +typedef WebServer ESPWebServer; +#else +#include +#endif + +const char* ssid = "........"; +const char* password = "........"; + +ESPWebServer server(80); + +static std::string htmlEncode(std::string data) { + const char *p = data.c_str(); + std::string rv = ""; + while(p && *p) { + char escapeChar = *p++; + switch(escapeChar) { + case '&': rv += "&"; break; + case '<': rv += "<"; break; + case '>': rv += ">"; break; + case '"': rv += """; break; + case '\'': rv += "'"; break; + case '/': rv += "/"; break; + default: rv += escapeChar; break; + } + } + return rv; +} + +void handleRoot() { + String rv; + rv += ""; + rv += ""; + rv += "Very simple file server"; + rv += ""; + rv += "

Very simple file server

"; + rv += "

This is a very simple file server to demonstrate the use of POST forms.

"; + rv += "

List existing files

"; + rv += "

See /public to list existing files and retrieve or edit them.

"; + rv += "

Upload new file

"; + rv += "

This form allows you to upload files (text, jpg and png supported best). It demonstrates multipart/form-data.

"; + rv += "
"; + rv += "file:
"; + rv += ""; + rv += "
"; + rv += ""; + rv += ""; + server.send(200, "text/html", rv); +} + +void handleFormEdit() { + bool hasFilename = server.hasArg("filename");; + String filename = server.arg("filename"); + String pathname = String("/public/") + filename; + if (server.hasArg("content") ){ + // Content has been edited. Save. + File file = SPIFFS.open(pathname.c_str(), "w"); + String content = server.arg("content"); + file.write((uint8_t *)content.c_str(), content.length()); + file.close(); + } + String content = server.arg("content"); + String rv; + rv += "Edit File\n"; + File file = SPIFFS.open(pathname.c_str()); + if (!hasFilename) { + rv += "

No filename specified.

\n"; + } else if (!file.available()) { + rv += "

File not found:"; + rv += pathname; + rv += "

\n"; + } else { + rv += "

Edit content of "; + rv += pathname; + rv += "

\n"; + rv += "
\n"; + rv += "\n"; + rv += "
"; + rv += ""; + rv += "
"; + } + rv += ""; + server.send(200, "text/html", rv); +} + +void handleFormUpload() { + Serial.println("handleUpload() called"); + server.send(200); +} + +File fsUploadFile; + +void handleFormUploadFile() { + Serial.println("handleUploadFile() called"); + HTTPUpload& upload = server.upload(); + if(upload.status == UPLOAD_FILE_START){ + String filename = String("/public/") + upload.filename; + Serial.printf("upload filename=%s\n", filename.c_str()); + Serial.print("handleFileUpload Name: "); Serial.println(filename); + fsUploadFile = SPIFFS.open(filename, "w"); // Open the file for writing in SPIFFS (create if it doesn't exist) + } else if(upload.status == UPLOAD_FILE_WRITE){ + Serial.printf("uploaded %d bytes\n", upload.currentSize); + if(fsUploadFile) + fsUploadFile.write(upload.buf, upload.currentSize); // Write the received bytes to the file + } else if(upload.status == UPLOAD_FILE_END){ + Serial.printf("upload total %d bytes\n", upload.totalSize); + if(fsUploadFile) { // If the file was successfully created + fsUploadFile.close(); // Close the file again + Serial.print("handleFileUpload Size: "); Serial.println(upload.totalSize); + server.sendHeader("Location","/public"); // Redirect the client to the success page + server.send(303); + } else { + server.send(500, "text/plain", "500: couldn't create file"); + } + server.send(200, "text/plain", "OK"); + } +} + +void handleDirectory() { + if (server.hasArg("filename")) { + // Download file + String pathname = "/public/" + server.arg("filename"); + File file = SPIFFS.open(pathname.c_str()); + const char *contentType = "application/binary"; + if (file.available()) { + if (pathname.endsWith(".txt")) { + contentType = "text/plain"; + } else if (pathname.endsWith(".jpg")) { + contentType = "image/jpeg"; + } else if (pathname.endsWith(".png")) { + contentType = "image/png"; + } + server.setContentLength(file.size()); + server.send(200, contentType); + size_t length; + do { + char buffer[256]; + length = file.read((uint8_t *)buffer, 256); + server.sendContent_P(buffer, length); + } while (length > 0); + } else { + server.send(404, "text/plain", "Not found."); + + } + return; + } + String rv; + rv += "File Listing\n"; + File d = SPIFFS.open("/public"); + if (!d.isDirectory()) { + rv += "

No files found.

\n"; + } else { + rv += "

File Listing

\n"; + rv += "
    \n"; + File f = d.openNextFile(); + while (f) { + std::string pathname(f.name()); + std::string filename = pathname.substr(8); // Remove /public/ + rv += "
  • "; + rv += String(filename.c_str()); + rv += ""; + if (pathname.rfind(".txt") != std::string::npos) { + rv += " [edit]"; + } + rv += "
  • "; + f = d.openNextFile(); + } + rv += "
"; + } + rv += ""; + server.send(200, "text/html", rv); +} + +void handleNotFound() { + String message = "File Not Found\n\n"; + message += "URI: "; + message += server.uri(); + message += "\nMethod: "; + message += (server.method() == HTTP_GET) ? "GET" : "POST"; + message += "\nArguments: "; + message += server.args(); + message += "\n"; + for (uint8_t i = 0; i < server.args(); i++) { + message += " " + server.argName(i) + ": " + server.arg(i) + "\n"; + } + server.send(404, "text/plain", message); +} + +void setup(void) { + Serial.begin(115200); + WiFi.mode(WIFI_STA); + WiFi.begin(ssid, password); + Serial.println(""); + + // Wait for connection + while (WiFi.status() != WL_CONNECTED) { + delay(500); + Serial.print("."); + } + Serial.println(""); + Serial.print("Connected to "); + Serial.println(ssid); + Serial.print("IP address: "); + Serial.println(WiFi.localIP()); + + if (MDNS.begin("esp32")) { + Serial.println("MDNS responder started"); + } + // Setup filesystem + if (!SPIFFS.begin(true)) Serial.println("Mounting SPIFFS failed"); + + server.on("/", handleRoot); + server.on("/upload", HTTP_POST, handleFormUpload, handleFormUploadFile); + server.on("/edit", HTTP_GET, handleFormEdit); + server.on("/edit", HTTP_POST, handleFormEdit); + server.on("/public", HTTP_GET, handleDirectory); + + server.onNotFound(handleNotFound); + + server.begin(); + Serial.println("HTTP server started"); +} + +void loop(void) { + server.handleClient(); +} diff --git a/platformio.ini b/platformio.ini index 1b3f69e..4767e0c 100644 --- a/platformio.ini +++ b/platformio.ini @@ -8,6 +8,6 @@ board = lolin32 lib_ldf_mode = deep+ lib_deps = https://github.com/jackjansen/esp32_https_server.git#bodyparser build_flags = -DHTTPS_LOGLEVEL=4 -DHTTPS_REQUEST_MAX_REQUEST_LENGTH=800 -src_filter = +<*> +<../examples/HelloServer> +src_filter = +<*> +<../examples/FormServer/> monitor_speed = 115200 upload_speed = 115200 \ No newline at end of file From 66328c497de01d4fbe3c6b4db3030836b0a0ddc6 Mon Sep 17 00:00:00 2001 From: Jack Jansen Date: Sun, 8 Mar 2020 21:02:57 +0100 Subject: [PATCH 29/54] Implemented url-encoded parameters (which are merged with URL parameters) --- src/ESPWebServer.cpp | 34 +++++++++++++++++++--------------- src/ESPWebServer.hpp | 1 + 2 files changed, 20 insertions(+), 15 deletions(-) diff --git a/src/ESPWebServer.cpp b/src/ESPWebServer.cpp index 4e517dc..7b0a7bd 100644 --- a/src/ESPWebServer.cpp +++ b/src/ESPWebServer.cpp @@ -142,8 +142,7 @@ HTTPUpload& ESPWebServer::upload() { } String ESPWebServer::pathArg(unsigned int i) { - ResourceParameters *params = _activeRequest->getParams(); - auto rv = params->getPathParameter(i); + auto rv = _activeParams->getPathParameter(i); return String(rv.c_str()); } @@ -171,17 +170,15 @@ String ESPWebServer::arg(String name) { return rv; } } - ResourceParameters *params = _activeRequest->getParams(); std::string value; - params->getQueryParameter(std::string(name.c_str()), value); + _activeParams->getQueryParameter(std::string(name.c_str()), value); HTTPS_LOGD("arg(%s) returns %s", name.c_str(), value.c_str()); return String(value.c_str()); } String ESPWebServer::arg(int i) { - ResourceParameters *params = _activeRequest->getParams(); int idx=0; - for (auto it=params->beginQueryParameters(); it != params->endQueryParameters(); it++, idx++) { + for (auto it=_activeParams->beginQueryParameters(); it != _activeParams->endQueryParameters(); it++, idx++) { if (idx == i) return String(it->second.c_str()); } @@ -189,9 +186,8 @@ String ESPWebServer::arg(int i) { } String ESPWebServer::argName(int i) { - ResourceParameters *params = _activeRequest->getParams(); int idx=0; - for (auto it=params->beginQueryParameters(); it != params->endQueryParameters(); it++, idx++) { + for (auto it=_activeParams->beginQueryParameters(); it != _activeParams->endQueryParameters(); it++, idx++) { if (idx == i) return String(it->first.c_str()); } @@ -199,13 +195,11 @@ String ESPWebServer::argName(int i) { } int ESPWebServer::args() { - ResourceParameters *params = _activeRequest->getParams(); - return params->getQueryParameterCount(); + return _activeParams->getQueryParameterCount(); } bool ESPWebServer::hasArg(String name) { - ResourceParameters *params = _activeRequest->getParams(); - bool rv = params->isQueryParameterSet(std::string(name.c_str())); + bool rv = _activeParams->isQueryParameterSet(std::string(name.c_str())); HTTPS_LOGD("hasArg(%s) returns %d", name.c_str(), (int)rv); return rv; } @@ -349,9 +343,11 @@ String ESPWebServer::urlDecode(const String& text) { void ESPWebServer::_handlerWrapper( httpsserver::HTTPRequest *req, httpsserver::HTTPResponse *res) { + BodyResourceParameters *bodyParams = nullptr; ESPWebServerNode *node = (ESPWebServerNode*)req->getResolvedNode(); node->_wrapper->_activeRequest = req; node->_wrapper->_activeResponse = res; + node->_wrapper->_activeParams = req->getParams(); node->_wrapper->_contentLength = CONTENT_LENGTH_NOT_SET; // POST form data needs to be handled specially if (req->getMethod() == "POST") { @@ -365,9 +361,16 @@ void ESPWebServer::_handlerWrapper( parser = new HTTPMultipartBodyParser(req); } if (contentType == "application/x-www-form-urlencoded") { - parser = new HTTPMultipartBodyParser(req); + parser = new HTTPURLEncodedBodyParser(req); } - BodyResourceParameters bodyFields; + // + // _activeParams should be the merger of the URL parameters and the body parameters. + // + bodyParams = new BodyResourceParameters(); + for (auto it = node->_wrapper->_activeParams->beginQueryParameters(); it != node->_wrapper->_activeParams->endQueryParameters(); it++) { + bodyParams->setQueryParameter(it->first, it->second); + } + node->_wrapper->_activeParams = bodyParams; while (parser && parser->nextField()) { std::string name = parser->getFieldName(); @@ -404,7 +407,7 @@ void ESPWebServer::_handlerWrapper( std::string bufString((char *)buf, readLength); value += bufString; } - bodyFields.setQueryParameter(name, value); + bodyParams->setQueryParameter(name, value); } } delete parser; @@ -412,6 +415,7 @@ void ESPWebServer::_handlerWrapper( node->_wrappedHandler(); node->_wrapper->_activeRequest = nullptr; node->_wrapper->_activeResponse = nullptr; + node->_wrapper->_activeParams = nullptr; } ESPWebServerNode::ESPWebServerNode( diff --git a/src/ESPWebServer.hpp b/src/ESPWebServer.hpp index 19e72e0..ad3f559 100644 --- a/src/ESPWebServer.hpp +++ b/src/ESPWebServer.hpp @@ -145,6 +145,7 @@ class ESPWebServer httpsserver::HTTPRequest *_activeRequest; httpsserver::HTTPResponse *_activeResponse; HTTPUpload *_activeUpload; + httpsserver::ResourceParameters *_activeParams; /** default node */ ESPWebServerNode *_notFoundNode; From 78c73fde35f4334152f1b47c461c58a572cfe1d6 Mon Sep 17 00:00:00 2001 From: Jack Jansen Date: Sun, 8 Mar 2020 22:32:59 +0100 Subject: [PATCH 30/54] Implemented basic authentication --- src/ESPWebServer.cpp | 50 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 49 insertions(+), 1 deletion(-) diff --git a/src/ESPWebServer.cpp b/src/ESPWebServer.cpp index 7b0a7bd..2bcfdfb 100644 --- a/src/ESPWebServer.cpp +++ b/src/ESPWebServer.cpp @@ -4,12 +4,30 @@ #include #include #include +#include using namespace httpsserver; /* Copy the content of Arduino String s into a newly allocated char array p */ #define ARDUINOTONEWCHARARR(s,p) {size_t sLen=s.length()+1;char *c=new char[sLen];c[sLen-1]=0;s.toCharArray(p,sLen);p=c;} +/* Helper function: trim whitespace from a string */ +static std::string trim(const std::string& s) { + auto wsfront=std::find_if_not(s.begin(),s.end(),[](int c){return std::isspace(c);}); + auto wsback=std::find_if_not(s.rbegin(),s.rend(),[](int c){return std::isspace(c);}).base(); + return (wsback<=wsfront ? std::string() : std::string(wsfront,wsback)); +} + +/* Helper function: base64 encoding */ +static std::string b64encode(const std::string& src) { + size_t bytesNeeded = base64_encode_expected_len(src.length()); + char *encoded = (char *)malloc(bytesNeeded); + base64_encode_chars(src.c_str(), src.length(), encoded); + std::string rv(encoded); + free(encoded); + return rv; +} + class BodyResourceParameters : public ResourceParameters { friend class ESPWebServer; }; @@ -69,7 +87,25 @@ void ESPWebServer::stop() { } bool ESPWebServer::authenticate(const char * username, const char * password) { - HTTPS_LOGE("authenticate(%s, %s) not yet implemented", username, password); + std::string authHeader = _activeRequest->getHeader("Authorization"); + if (authHeader == "") return false; + if (authHeader.substr(0, 5) == "Basic") { + std::string authReq = authHeader.substr(6); + authReq = trim(authReq); + std::string toEncode(username); + toEncode += ":"; + toEncode += password; + std::string encoded = b64encode(toEncode); + return (encoded == authReq); + } else if (authHeader.substr(0, 6) == "Digest") { + HTTPS_LOGE("Only BASIC_AUTH implemented"); +#if 0 + std::string authReq = authHeader.substr(6); + std::string realm = _extractParam(authReq, "realm=\""); + std::string hash = credentialHash(username, _realm, password); + return authenticateDigest(username, hash); +#endif + } return false; } @@ -83,6 +119,18 @@ void ESPWebServer::requestAuthentication(HTTPAuthMethod mode, const char* realm, _activeResponse->setHeader("WWW-Authenticate", authArg); } else { HTTPS_LOGE("Only BASIC_AUTH implemented"); +#if 0 + _snonce = _getRandomHexString(); + _sopaque = _getRandomHexString(); + std::string authArg = "Digest realm=\""; + authArg += realm; + authArg += "\", qop=\"auth\", nonce=\""; + authArg += _snonce; + authArg += "\", opaque=\""; + authArg += _sopaque; + authArg += "\""; + _activeResponse->setHeader("WWW-Authenticate", authArg); +#endif } } From dc8cca8ed79860122c1c65879179c77bba43d57d Mon Sep 17 00:00:00 2001 From: Jack Jansen Date: Sun, 8 Mar 2020 23:13:14 +0100 Subject: [PATCH 31/54] Fixed basic authentication, and test it in the edit form example --- examples/FormServer/mainFormServer.cpp | 1 + platformio.ini | 2 ++ src/ESPWebServer.cpp | 6 ++++-- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/examples/FormServer/mainFormServer.cpp b/examples/FormServer/mainFormServer.cpp index 3fa0383..3500d0c 100644 --- a/examples/FormServer/mainFormServer.cpp +++ b/examples/FormServer/mainFormServer.cpp @@ -55,6 +55,7 @@ void handleRoot() { } void handleFormEdit() { + if (!server.authenticate("admin", "admin")) return server.requestAuthentication(); bool hasFilename = server.hasArg("filename");; String filename = server.arg("filename"); String pathname = String("/public/") + filename; diff --git a/platformio.ini b/platformio.ini index 4767e0c..5f365e0 100644 --- a/platformio.ini +++ b/platformio.ini @@ -9,5 +9,7 @@ lib_ldf_mode = deep+ lib_deps = https://github.com/jackjansen/esp32_https_server.git#bodyparser build_flags = -DHTTPS_LOGLEVEL=4 -DHTTPS_REQUEST_MAX_REQUEST_LENGTH=800 src_filter = +<*> +<../examples/FormServer/> +debug_tool = minimodule +upload_protocol = minimodule monitor_speed = 115200 upload_speed = 115200 \ No newline at end of file diff --git a/src/ESPWebServer.cpp b/src/ESPWebServer.cpp index 2bcfdfb..7e84c32 100644 --- a/src/ESPWebServer.cpp +++ b/src/ESPWebServer.cpp @@ -21,8 +21,9 @@ static std::string trim(const std::string& s) { /* Helper function: base64 encoding */ static std::string b64encode(const std::string& src) { size_t bytesNeeded = base64_encode_expected_len(src.length()); - char *encoded = (char *)malloc(bytesNeeded); - base64_encode_chars(src.c_str(), src.length(), encoded); + char *encoded = (char *)malloc(bytesNeeded+1); + int bytesUsed = base64_encode_chars(src.c_str(), src.length(), encoded); + encoded[bytesUsed] = '\0'; std::string rv(encoded); free(encoded); return rv; @@ -132,6 +133,7 @@ void ESPWebServer::requestAuthentication(HTTPAuthMethod mode, const char* realm, _activeResponse->setHeader("WWW-Authenticate", authArg); #endif } + send(401, "text/html", authFailMsg); } void ESPWebServer::on(const String &uri, THandlerFunction handler) { From d1a3062f27e1ba9f720c061b078ab6ad55e5e917 Mon Sep 17 00:00:00 2001 From: Jack Jansen Date: Sun, 8 Mar 2020 23:26:01 +0100 Subject: [PATCH 32/54] Do basic auth using the infrastructure already implemented in esp32_https_server --- platformio.ini | 4 ++-- src/ESPWebServer.cpp | 28 +++------------------------- 2 files changed, 5 insertions(+), 27 deletions(-) diff --git a/platformio.ini b/platformio.ini index 5f365e0..48f9b7e 100644 --- a/platformio.ini +++ b/platformio.ini @@ -9,7 +9,7 @@ lib_ldf_mode = deep+ lib_deps = https://github.com/jackjansen/esp32_https_server.git#bodyparser build_flags = -DHTTPS_LOGLEVEL=4 -DHTTPS_REQUEST_MAX_REQUEST_LENGTH=800 src_filter = +<*> +<../examples/FormServer/> -debug_tool = minimodule -upload_protocol = minimodule +; debug_tool = minimodule +; upload_protocol = minimodule monitor_speed = 115200 upload_speed = 115200 \ No newline at end of file diff --git a/src/ESPWebServer.cpp b/src/ESPWebServer.cpp index 7e84c32..2173f31 100644 --- a/src/ESPWebServer.cpp +++ b/src/ESPWebServer.cpp @@ -11,24 +11,6 @@ using namespace httpsserver; /* Copy the content of Arduino String s into a newly allocated char array p */ #define ARDUINOTONEWCHARARR(s,p) {size_t sLen=s.length()+1;char *c=new char[sLen];c[sLen-1]=0;s.toCharArray(p,sLen);p=c;} -/* Helper function: trim whitespace from a string */ -static std::string trim(const std::string& s) { - auto wsfront=std::find_if_not(s.begin(),s.end(),[](int c){return std::isspace(c);}); - auto wsback=std::find_if_not(s.rbegin(),s.rend(),[](int c){return std::isspace(c);}).base(); - return (wsback<=wsfront ? std::string() : std::string(wsfront,wsback)); -} - -/* Helper function: base64 encoding */ -static std::string b64encode(const std::string& src) { - size_t bytesNeeded = base64_encode_expected_len(src.length()); - char *encoded = (char *)malloc(bytesNeeded+1); - int bytesUsed = base64_encode_chars(src.c_str(), src.length(), encoded); - encoded[bytesUsed] = '\0'; - std::string rv(encoded); - free(encoded); - return rv; -} - class BodyResourceParameters : public ResourceParameters { friend class ESPWebServer; }; @@ -91,13 +73,9 @@ bool ESPWebServer::authenticate(const char * username, const char * password) { std::string authHeader = _activeRequest->getHeader("Authorization"); if (authHeader == "") return false; if (authHeader.substr(0, 5) == "Basic") { - std::string authReq = authHeader.substr(6); - authReq = trim(authReq); - std::string toEncode(username); - toEncode += ":"; - toEncode += password; - std::string encoded = b64encode(toEncode); - return (encoded == authReq); + std::string reqUser = _activeRequest->getBasicAuthUser(); + std::string reqPassword = _activeRequest->getBasicAuthPassword(); + return (username == reqUser && password == reqPassword); } else if (authHeader.substr(0, 6) == "Digest") { HTTPS_LOGE("Only BASIC_AUTH implemented"); #if 0 From 905e6cf02d9b5fe0e043d4a8df2460744e19305a Mon Sep 17 00:00:00 2001 From: Jack Jansen Date: Sun, 8 Mar 2020 23:43:18 +0100 Subject: [PATCH 33/54] Changed example to use serveStatic to serve static files --- examples/FormServer/mainFormServer.cpp | 33 ++++---------------------- 1 file changed, 4 insertions(+), 29 deletions(-) diff --git a/examples/FormServer/mainFormServer.cpp b/examples/FormServer/mainFormServer.cpp index 3500d0c..f3d309c 100644 --- a/examples/FormServer/mainFormServer.cpp +++ b/examples/FormServer/mainFormServer.cpp @@ -136,33 +136,6 @@ void handleFormUploadFile() { } void handleDirectory() { - if (server.hasArg("filename")) { - // Download file - String pathname = "/public/" + server.arg("filename"); - File file = SPIFFS.open(pathname.c_str()); - const char *contentType = "application/binary"; - if (file.available()) { - if (pathname.endsWith(".txt")) { - contentType = "text/plain"; - } else if (pathname.endsWith(".jpg")) { - contentType = "image/jpeg"; - } else if (pathname.endsWith(".png")) { - contentType = "image/png"; - } - server.setContentLength(file.size()); - server.send(200, contentType); - size_t length; - do { - char buffer[256]; - length = file.read((uint8_t *)buffer, 256); - server.sendContent_P(buffer, length); - } while (length > 0); - } else { - server.send(404, "text/plain", "Not found."); - - } - return; - } String rv; rv += "File Listing\n"; File d = SPIFFS.open("/public"); @@ -175,8 +148,8 @@ void handleDirectory() { while (f) { std::string pathname(f.name()); std::string filename = pathname.substr(8); // Remove /public/ - rv += "
  • "; rv += String(filename.c_str()); rv += ""; @@ -236,7 +209,9 @@ void setup(void) { server.on("/upload", HTTP_POST, handleFormUpload, handleFormUploadFile); server.on("/edit", HTTP_GET, handleFormEdit); server.on("/edit", HTTP_POST, handleFormEdit); + // Note: /public (without trailing /) gives directory listing, but /public/... retrieves static files. server.on("/public", HTTP_GET, handleDirectory); + server.serveStatic("/public/", SPIFFS, "/public/"); server.onNotFound(handleNotFound); From a9d4489f1b5d7db9ea2fb21c66c7b0209f132f7c Mon Sep 17 00:00:00 2001 From: Jack Jansen Date: Mon, 9 Mar 2020 00:12:32 +0100 Subject: [PATCH 34/54] Getting started on static page serving --- src/ESPWebServer.cpp | 80 ++++++++++++++++++++++++++++++++++++++++++++ src/ESPWebServer.hpp | 25 ++++++++++++++ 2 files changed, 105 insertions(+) diff --git a/src/ESPWebServer.cpp b/src/ESPWebServer.cpp index 2173f31..3f8f409 100644 --- a/src/ESPWebServer.cpp +++ b/src/ESPWebServer.cpp @@ -28,6 +28,19 @@ struct { {HTTP_OPTIONS, "OPTIONS"}, }; +// We need to specify some content-type mapping, so the resources get delivered with the +// right content type and are displayed correctly in the browser +char contentTypes[][2][32] = { + {".html", "text/html"}, + {".txt", "text/plain"}, + {".css", "text/css"}, + {".js", "application/javascript"}, + {".json", "application/json"}, + {".png", "image/png"}, + {".jpg", "image/jpg"}, + {"", ""} +}; + ESPWebServer::ESPWebServer(HTTPServer *server) : _server(server), _contentLength(0) @@ -138,6 +151,8 @@ void ESPWebServer::on(const String &uri, HTTPMethod method, THandlerFunction fn, void ESPWebServer::serveStatic(const char* uri, fs::FS& fs, const char* path, const char* cache_header) { HTTPS_LOGE("serveStatic() not implemented"); + ESPWebServerStaticNode *node = new ESPWebServerStaticNode(this, std::string(uri), fs, std::string(path), std::string(cache_header)); + _server->registerNode(node); } void ESPWebServer::onNotFound(THandlerFunction fn) { @@ -446,6 +461,55 @@ void ESPWebServer::_handlerWrapper( node->_wrapper->_activeParams = nullptr; } +/** + * This handler function will try to load the requested resource from SPIFFS's /public folder. + * + * If the method is not GET, it will throw 405, if the file is not found, it will throw 404. + */ +void ESPWebServer::_staticPageHandler(HTTPRequest * req, HTTPResponse * res) { + assert(req->getMethod() == "GET"); + ESPWebServerStaticNode *node = (ESPWebServerNode*)req->getResolvedNode(); + // Redirect / to /index.html + std::string reqFile = req->getRequestString()=="/" ? "/index.html" : req->getRequestString(); + + // Try to open the file + std::string filename = node->_filePath + reqFile; + + // Check if the file exists + if (!node->_fileSystem.exists(filename.c_str())) { + // Send "404 Not Found" as response, as the file doesn't seem to exist + res->setStatusCode(404); + res->setStatusText("Not found"); + res->println("404 Not Found"); + return; + } + + File file = node->_fileSystem.open(filename.c_str()); + + // Set length + res->setHeader("Content-Length", httpsserver::intToString(file.size())); + + // Content-Type is guessed using the definition of the contentTypes-table defined above + int cTypeIdx = 0; + do { + if(reqFile.rfind(contentTypes[cTypeIdx][0])!=std::string::npos) { + res->setHeader("Content-Type", contentTypes[cTypeIdx][1]); + break; + } + cTypeIdx+=1; + } while(strlen(contentTypes[cTypeIdx][0])>0); + + // Read the file and write it to the response + uint8_t buffer[256]; + size_t length = 0; + do { + length = file.read(buffer, 256); + res->write(buffer, length); + } while (length > 0); + + file.close(); +} + ESPWebServerNode::ESPWebServerNode( ESPWebServer *server, const std::string &path, @@ -463,3 +527,19 @@ ESPWebServerNode::ESPWebServerNode( ESPWebServerNode::~ESPWebServerNode() { } + +ESPWebServerStaticNode::ESPWebServerStaticNode( + ESPWebServer *server, + const std::string& urlPath, + FS& fs, + const std::string& filePath, + const std::string& cache_header) : + ResourceNode(urlPath, "GET", &(ESPWebServer::_staticPageHandler), ""), + _filePath(filePath), + _fileSystem(fs), + _cache_header(cache_header) +{ +} + +ESPWebServerStaticNode::~ESPWebServerStaticNode() { +} diff --git a/src/ESPWebServer.hpp b/src/ESPWebServer.hpp index ad3f559..ceadc04 100644 --- a/src/ESPWebServer.hpp +++ b/src/ESPWebServer.hpp @@ -128,10 +128,14 @@ class ESPWebServer protected: friend class ESPWebServerNode; + friend class ESPWebServerStaticNode; /** The wrapper function that maps on() calls */ static void _handlerWrapper(httpsserver::HTTPRequest *req, httpsserver::HTTPResponse *res); + /** The wrapper function that maps on() calls */ + static void _staticPageHandler(httpsserver::HTTPRequest *req, httpsserver::HTTPResponse *res); + /** Add standard headers */ void _standardHeaders(); @@ -175,4 +179,25 @@ class ESPWebServerNode : public httpsserver::ResourceNode { const THandlerFunction _wrappedUploadHandler; }; +class ESPWebServerStaticNode : public httpsserver::ResourceNode { +public: + ESPWebServerStaticNode( + ESPWebServer *server, + const std::string& urlPath, + FS& fs, + const std::string& filePath, + const std::string& cache_header); + virtual ~ESPWebServerStaticNode(); + +protected: + friend class ESPWebServer; + ESPWebServer *_wrapper; + std::string _filePath; + FS& _fileSystem; + std::string _cache_header; + +}; + +ESPWebServerStaticNode(this, std::string(uri), fs, std::string(path), std::string(cache_header)); + #endif //ESPWEBSERVER_H \ No newline at end of file From 5da03f05df1fc2cb5ddabfdd1ca0d8299b8a12f7 Mon Sep 17 00:00:00 2001 From: Jack Jansen Date: Mon, 9 Mar 2020 00:17:32 +0100 Subject: [PATCH 35/54] Fixed to compile. Still untested --- src/ESPWebServer.cpp | 5 ++++- src/ESPWebServer.hpp | 2 -- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/ESPWebServer.cpp b/src/ESPWebServer.cpp index 3f8f409..afb6260 100644 --- a/src/ESPWebServer.cpp +++ b/src/ESPWebServer.cpp @@ -468,7 +468,10 @@ void ESPWebServer::_handlerWrapper( */ void ESPWebServer::_staticPageHandler(HTTPRequest * req, HTTPResponse * res) { assert(req->getMethod() == "GET"); - ESPWebServerStaticNode *node = (ESPWebServerNode*)req->getResolvedNode(); + ESPWebServerStaticNode *node = (ESPWebServerStaticNode*)req->getResolvedNode(); + // xxxjack remove urlpath bits from reqFile + // xxxjack add index.htm if needed + // xxxjack prepend filepath // Redirect / to /index.html std::string reqFile = req->getRequestString()=="/" ? "/index.html" : req->getRequestString(); diff --git a/src/ESPWebServer.hpp b/src/ESPWebServer.hpp index ceadc04..dd81b1d 100644 --- a/src/ESPWebServer.hpp +++ b/src/ESPWebServer.hpp @@ -198,6 +198,4 @@ class ESPWebServerStaticNode : public httpsserver::ResourceNode { }; -ESPWebServerStaticNode(this, std::string(uri), fs, std::string(path), std::string(cache_header)); - #endif //ESPWEBSERVER_H \ No newline at end of file From 73cccc06d35360d6e08e4321f26e2d372282f77b Mon Sep 17 00:00:00 2001 From: Jack Jansen Date: Tue, 10 Mar 2020 00:23:13 +0100 Subject: [PATCH 36/54] Static file serving working, for 1 level of directories --- platformio.ini | 4 ++-- src/ESPWebServer.cpp | 13 ++++++++++--- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/platformio.ini b/platformio.ini index 48f9b7e..5f365e0 100644 --- a/platformio.ini +++ b/platformio.ini @@ -9,7 +9,7 @@ lib_ldf_mode = deep+ lib_deps = https://github.com/jackjansen/esp32_https_server.git#bodyparser build_flags = -DHTTPS_LOGLEVEL=4 -DHTTPS_REQUEST_MAX_REQUEST_LENGTH=800 src_filter = +<*> +<../examples/FormServer/> -; debug_tool = minimodule -; upload_protocol = minimodule +debug_tool = minimodule +upload_protocol = minimodule monitor_speed = 115200 upload_speed = 115200 \ No newline at end of file diff --git a/src/ESPWebServer.cpp b/src/ESPWebServer.cpp index afb6260..e724b2b 100644 --- a/src/ESPWebServer.cpp +++ b/src/ESPWebServer.cpp @@ -150,8 +150,14 @@ void ESPWebServer::on(const String &uri, HTTPMethod method, THandlerFunction fn, } void ESPWebServer::serveStatic(const char* uri, fs::FS& fs, const char* path, const char* cache_header) { - HTTPS_LOGE("serveStatic() not implemented"); - ESPWebServerStaticNode *node = new ESPWebServerStaticNode(this, std::string(uri), fs, std::string(path), std::string(cache_header)); + std::string wsUri(uri); + std::string wsPath(path); + if (wsUri[wsUri.length()-1] == '/') { + // serving a whole directory + wsUri += "*"; + if (wsPath[wsPath.length()-1] != '/') wsPath += "/"; + } + ESPWebServerStaticNode *node = new ESPWebServerStaticNode(this, wsUri, fs, wsPath, std::string(cache_header?cache_header:"")); _server->registerNode(node); } @@ -473,7 +479,8 @@ void ESPWebServer::_staticPageHandler(HTTPRequest * req, HTTPResponse * res) { // xxxjack add index.htm if needed // xxxjack prepend filepath // Redirect / to /index.html - std::string reqFile = req->getRequestString()=="/" ? "/index.html" : req->getRequestString(); + std::string reqFile; + if (!req->getParams()->getPathParameter(0, reqFile)) reqFile = "index.html"; // Try to open the file std::string filename = node->_filePath + reqFile; From 195aaef3fc63e6d8859797ff8fb8adeb0bde71b4 Mon Sep 17 00:00:00 2001 From: Jack Jansen Date: Tue, 10 Mar 2020 23:36:12 +0100 Subject: [PATCH 37/54] Updated for current state of things --- README.md | 34 ++++++++++++++-------------------- 1 file changed, 14 insertions(+), 20 deletions(-) diff --git a/README.md b/README.md index 4905f01..4d6b049 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# esp32_https_server_compat +# esp32\_https\_server\_compat This library is a wrapper around the [TLS-enabled web server for the ESP32 using the Arduino core](https://github.com/fhessel/esp32_https_server), to make it compatible with the [default Webserver API](https://github.com/espressif/arduino-esp32/tree/master/libraries/WebServer). @@ -8,7 +8,7 @@ The setup depends on the IDE that you're using. ### Using PlatformIO (recommended) -If you're using PlatformIO, just add esp32_https_server_compat to the library depenendencies in your platform.ini: +If you're using PlatformIO, just add `esp32\_https\_server\_compat` to the library depenendencies in your `platform.ini`: ```ini [env:myenv] @@ -37,24 +37,18 @@ void loop() { } ``` -More information and examples can be found in the default WebServer's [repository](https://github.com/espressif/arduino-esp32/tree/master/libraries/WebServer). +To use the HTTPS server use `` and `ESPWebServerSecure` in stead of `ESPWebServer`. + +More information and examples can be found in the default WebServer's [repository](https://github.com/espressif/arduino-esp32/tree/master/libraries/WebServer). There are two minimal examples (more test programs, really) in the [examples](examples) directory. ## State of Development -This wrapper is still very WIP. - -| Function | State | Comment | -| -------- | ----- | ------- | -| Starting and stopping the server | ✅ | (but not tested) | -| Handling basic requests | ✅ | `on(...)` | -| Handling 404 | ✅ | `onNotFound(...)` | -| Providing access to request properties | ✅ | `uri()`, `method()` | -| Handling file uploads | ❌ | `onFileUpload(...)`, `upload()`, and `on()` with 4 parameters | -| Handling headers | ❌ | `header()`, `headerName()`, `headers()` etc. | -| Handling arguments | ❌ | `arg()`, `argName()`, `hasArg()` etc. | -| Handling forms | ❌ | Needs [esp32_https_server#29](https://github.com/fhessel/esp32_https_server/issues/29) first. | -| Sending responses | ❌ | `send()` etc. | -| CORS and cross-origin | ❌ | Needs headers first | -| Streaming files | ❌ | `streamFile()` | -| `FS` support | ❌ | | -| TLS | ❌ | Needs `ESPWebServerSecure` that extends `ESPWebServer` | +The following issues are known: + +- `serveStatic()` will serve only a single file or a single directory (as opposed to serving a whole subtree in the default WebServer). +- `serveStatic()` does not implement automatic gzip support. +- `serveStatic()` knows about only a limited set of mimetypes for file extensions. +- `authenticate()` and `requestAuthentication()` handle only `Basic` authentication, not `Digest` authentication. +- `sendHeader()` ignores the `first=true` parameter. +- `collectHeaders()` is not implemented. +- Handling of `POST` forms with mimetype `application/x-www-form-urlencoded` is memory-inefficient: the whole POST body is loaded into memory twice. \ No newline at end of file From ac5f6cded9ed543b20ce710d85fa6449ecec8a90 Mon Sep 17 00:00:00 2001 From: Jack Jansen Date: Tue, 10 Mar 2020 23:36:37 +0100 Subject: [PATCH 38/54] A bit of cleanup --- examples/FormServer/FormServer.ino | 2 +- examples/FormServer/mainFormServer.cpp | 2 +- examples/HelloServer/HelloServer.ino | 2 +- examples/HelloServer/mainHelloServer.cpp | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/examples/FormServer/FormServer.ino b/examples/FormServer/FormServer.ino index fd50093..213e86b 100644 --- a/examples/FormServer/FormServer.ino +++ b/examples/FormServer/FormServer.ino @@ -3,7 +3,7 @@ #include #include #include -#if 0 +#ifdef USE_DEFAULT_WEBSERVER #include #else #include diff --git a/examples/FormServer/mainFormServer.cpp b/examples/FormServer/mainFormServer.cpp index f3d309c..572d8da 100644 --- a/examples/FormServer/mainFormServer.cpp +++ b/examples/FormServer/mainFormServer.cpp @@ -3,7 +3,7 @@ #include #include #include -#if 0 +#ifdef USE_DEFAULT_WEBSERVER #include typedef WebServer ESPWebServer; #else diff --git a/examples/HelloServer/HelloServer.ino b/examples/HelloServer/HelloServer.ino index 780e426..6461c9a 100644 --- a/examples/HelloServer/HelloServer.ino +++ b/examples/HelloServer/HelloServer.ino @@ -1,7 +1,7 @@ #include #include #include -#if 0 +#ifdef USE_DEFAULT_WEBSERVER #include #else #include diff --git a/examples/HelloServer/mainHelloServer.cpp b/examples/HelloServer/mainHelloServer.cpp index ef75039..5e96469 100644 --- a/examples/HelloServer/mainHelloServer.cpp +++ b/examples/HelloServer/mainHelloServer.cpp @@ -2,7 +2,7 @@ #include #include #include -#if 0 +#ifdef USE_DEFAULT_WEBSERVER #include typedef WebServer ESPWebServer; #else From 23238649b87b77cddb408d481b320d350087f550 Mon Sep 17 00:00:00 2001 From: Jack Jansen Date: Tue, 10 Mar 2020 23:36:53 +0100 Subject: [PATCH 39/54] Cleanup --- platformio.ini | 39 +++++++++++++++++++++++++++++++++++++-- src/ESPWebServer.cpp | 8 ++------ 2 files changed, 39 insertions(+), 8 deletions(-) diff --git a/platformio.ini b/platformio.ini index 5f365e0..3575c74 100644 --- a/platformio.ini +++ b/platformio.ini @@ -1,7 +1,7 @@ [platformio] -default_envs = lolin32 +default_envs = lolin32-FormServer -[env:lolin32] +[env:lolin32-FormServer-minimodule] framework = arduino platform = espressif32@>=1.11 board = lolin32 @@ -12,4 +12,39 @@ src_filter = +<*> +<../examples/FormServer/> debug_tool = minimodule upload_protocol = minimodule monitor_speed = 115200 +upload_speed = 115200 + +[env:lolin32-FormServer] +framework = arduino +platform = espressif32@>=1.11 +board = lolin32 +lib_ldf_mode = deep+ +lib_deps = https://github.com/jackjansen/esp32_https_server.git#bodyparser +build_flags = -DHTTPS_LOGLEVEL=4 -DHTTPS_REQUEST_MAX_REQUEST_LENGTH=800 +src_filter = +<*> +<../examples/FormServer/> +monitor_speed = 115200 +upload_speed = 115200 + +[env:lolin32-HelloServer-minimodule] +framework = arduino +platform = espressif32@>=1.11 +board = lolin32 +lib_ldf_mode = deep+ +lib_deps = https://github.com/jackjansen/esp32_https_server.git#bodyparser +build_flags = -DHTTPS_LOGLEVEL=4 -DHTTPS_REQUEST_MAX_REQUEST_LENGTH=800 +src_filter = +<*> +<../examples/HelloServer/> +debug_tool = minimodule +upload_protocol = minimodule +monitor_speed = 115200 +upload_speed = 115200 + +[env:lolin32-HelloServer] +framework = arduino +platform = espressif32@>=1.11 +board = lolin32 +lib_ldf_mode = deep+ +lib_deps = https://github.com/jackjansen/esp32_https_server.git#bodyparser +build_flags = -DHTTPS_LOGLEVEL=4 -DHTTPS_REQUEST_MAX_REQUEST_LENGTH=800 +src_filter = +<*> +<../examples/HelloServer/> +monitor_speed = 115200 upload_speed = 115200 \ No newline at end of file diff --git a/src/ESPWebServer.cpp b/src/ESPWebServer.cpp index e724b2b..0d80ec8 100644 --- a/src/ESPWebServer.cpp +++ b/src/ESPWebServer.cpp @@ -103,7 +103,6 @@ bool ESPWebServer::authenticate(const char * username, const char * password) { void ESPWebServer::requestAuthentication(HTTPAuthMethod mode, const char* realm, const String& authFailMsg) { if (realm == NULL) realm = "Login Required"; - HTTPS_LOGD("requestAuthentication(%d, %s)\n", mode, realm); if (mode == BASIC_AUTH) { std::string authArg = "Basic realm=\""; authArg += realm; @@ -215,13 +214,11 @@ String ESPWebServer::arg(String name) { buffer[readLength] = 0; rv += buffer; } - HTTPS_LOGD("arg(\"plain\") returns %d bytes", rv.length()); return rv; } } std::string value; _activeParams->getQueryParameter(std::string(name.c_str()), value); - HTTPS_LOGD("arg(%s) returns %s", name.c_str(), value.c_str()); return String(value.c_str()); } @@ -249,12 +246,11 @@ int ESPWebServer::args() { bool ESPWebServer::hasArg(String name) { bool rv = _activeParams->isQueryParameterSet(std::string(name.c_str())); - HTTPS_LOGD("hasArg(%s) returns %d", name.c_str(), (int)rv); return rv; } void ESPWebServer::collectHeaders(const char* headerKeys[], const size_t headerKeysCount) { - HTTPS_LOGW("collectHeaders() not implemented, but probably not needed"); + HTTPS_LOGE("collectHeaders() not implemented"); } String ESPWebServer::header(String name) { @@ -367,7 +363,7 @@ void ESPWebServer::setContentLength(const size_t contentLength) { void ESPWebServer::sendHeader(const String& name, const String& value, bool first) { if (first) { - HTTPS_LOGW("sendHeader(..., first=true) not implemented"); + HTTPS_LOGE("sendHeader(..., first=true) not implemented"); } _activeResponse->setHeader(name.c_str(), value.c_str()); } From 0df88009f711fdef110ea1afeb964879822c4297 Mon Sep 17 00:00:00 2001 From: Jack Jansen Date: Tue, 10 Mar 2020 23:47:41 +0100 Subject: [PATCH 40/54] This branch has references to jackjansen for URLs, etc --- library.json | 9 +++++++-- library.properties | 4 ++-- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/library.json b/library.json index e262284..adb3c7c 100644 --- a/library.json +++ b/library.json @@ -5,6 +5,11 @@ "name": "Frank Hessel", "email": "frank@fhessel.de", "maintainer": true + }, + { + "name": "Jack Jansen", + "email": "Jack.Jansen@cwi.nl", + "maintainer": true } ], "keywords": "communication, esp32, http, https, server, ssl, tls, webserver, websockets", @@ -12,12 +17,12 @@ "repository": { "type": "git", - "url": "https://github.com/fhessel/esp32_https_server_compat.git" + "url": "https://github.com/jackjansen/esp32_https_server_compat.git" }, "dependencies": [ { "name": "esp32_https_server", - "version": "https://github.com/jackjansen/esp32_https_server.git#exp-jack-compat" + "version": "https://github.com/jackjansen/esp32_https_server.git#bodyparser" } ], "license": "MIT", diff --git a/library.properties b/library.properties index cf8a48f..4b76d90 100644 --- a/library.properties +++ b/library.properties @@ -1,10 +1,10 @@ name=ESP32 HTTP(S) Webserver (Compatibility Layer) version=0.3.0 -author=Frank Hessel +author=Frank Hessel , Jack Jansen maintainer=Frank Hessel sentence=An Arduino library for an alternative ESP32 HTTP/HTTPS web server implementation paragraph=This library is a wrapper around esp32_https_server that provides the same API as the default Webserver library. category=Communication -url=https://github.com/fhessel/esp32_https_server_compat +url=https://github.com/jackjansen/esp32_https_server_compat architectures=esp32 includes=ESPWebserver.hpp \ No newline at end of file From 0fe906e14fcf3b91779e68f299f4578500cf9c7d Mon Sep 17 00:00:00 2001 From: Jack Jansen Date: Tue, 10 Mar 2020 23:50:09 +0100 Subject: [PATCH 41/54] Changed URL references to fhessel --- library.json | 4 ++-- library.properties | 2 +- platformio.ini | 8 ++++---- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/library.json b/library.json index adb3c7c..8d2be79 100644 --- a/library.json +++ b/library.json @@ -17,12 +17,12 @@ "repository": { "type": "git", - "url": "https://github.com/jackjansen/esp32_https_server_compat.git" + "url": "https://github.com/fhessel/esp32_https_server_compat.git" }, "dependencies": [ { "name": "esp32_https_server", - "version": "https://github.com/jackjansen/esp32_https_server.git#bodyparser" + "version": "https://github.com/fhessel/esp32_https_server.git" } ], "license": "MIT", diff --git a/library.properties b/library.properties index 4b76d90..a6a0699 100644 --- a/library.properties +++ b/library.properties @@ -5,6 +5,6 @@ maintainer=Frank Hessel sentence=An Arduino library for an alternative ESP32 HTTP/HTTPS web server implementation paragraph=This library is a wrapper around esp32_https_server that provides the same API as the default Webserver library. category=Communication -url=https://github.com/jackjansen/esp32_https_server_compat +url=https://github.com/fhessel/esp32_https_server_compat architectures=esp32 includes=ESPWebserver.hpp \ No newline at end of file diff --git a/platformio.ini b/platformio.ini index 3575c74..b8dd49e 100644 --- a/platformio.ini +++ b/platformio.ini @@ -6,7 +6,7 @@ framework = arduino platform = espressif32@>=1.11 board = lolin32 lib_ldf_mode = deep+ -lib_deps = https://github.com/jackjansen/esp32_https_server.git#bodyparser +lib_deps = https://github.com/fhessel/esp32_https_server.git build_flags = -DHTTPS_LOGLEVEL=4 -DHTTPS_REQUEST_MAX_REQUEST_LENGTH=800 src_filter = +<*> +<../examples/FormServer/> debug_tool = minimodule @@ -19,7 +19,7 @@ framework = arduino platform = espressif32@>=1.11 board = lolin32 lib_ldf_mode = deep+ -lib_deps = https://github.com/jackjansen/esp32_https_server.git#bodyparser +lib_deps = https://github.com/fhessel/esp32_https_server.git build_flags = -DHTTPS_LOGLEVEL=4 -DHTTPS_REQUEST_MAX_REQUEST_LENGTH=800 src_filter = +<*> +<../examples/FormServer/> monitor_speed = 115200 @@ -30,7 +30,7 @@ framework = arduino platform = espressif32@>=1.11 board = lolin32 lib_ldf_mode = deep+ -lib_deps = https://github.com/jackjansen/esp32_https_server.git#bodyparser +lib_deps = https://github.com/fhessel/esp32_https_server.git build_flags = -DHTTPS_LOGLEVEL=4 -DHTTPS_REQUEST_MAX_REQUEST_LENGTH=800 src_filter = +<*> +<../examples/HelloServer/> debug_tool = minimodule @@ -43,7 +43,7 @@ framework = arduino platform = espressif32@>=1.11 board = lolin32 lib_ldf_mode = deep+ -lib_deps = https://github.com/jackjansen/esp32_https_server.git#bodyparser +lib_deps = https://github.com/fhessel/esp32_https_server.git build_flags = -DHTTPS_LOGLEVEL=4 -DHTTPS_REQUEST_MAX_REQUEST_LENGTH=800 src_filter = +<*> +<../examples/HelloServer/> monitor_speed = 115200 From d0d1353cccd53be2ca22daaa8697c685ff8c0dd0 Mon Sep 17 00:00:00 2001 From: Jack Jansen Date: Tue, 10 Mar 2020 23:52:37 +0100 Subject: [PATCH 42/54] Got rid of ino/cpp workaround that only I seem to need --- examples/FormServer/FormServer.ino | 215 +++++++++++++++++++++- examples/FormServer/mainFormServer.cpp | 224 ----------------------- examples/HelloServer/HelloServer.ino | 155 ++++++++++++++++ examples/HelloServer/mainHelloServer.cpp | 164 ----------------- 4 files changed, 369 insertions(+), 389 deletions(-) delete mode 100644 examples/FormServer/mainFormServer.cpp delete mode 100644 examples/HelloServer/mainHelloServer.cpp diff --git a/examples/FormServer/FormServer.ino b/examples/FormServer/FormServer.ino index 213e86b..c20c661 100644 --- a/examples/FormServer/FormServer.ino +++ b/examples/FormServer/FormServer.ino @@ -1,10 +1,223 @@ -#include #include #include #include #include #ifdef USE_DEFAULT_WEBSERVER #include +typedef WebServer ESPWebServer; #else #include #endif + +const char* ssid = "........"; +const char* password = "........"; + +ESPWebServer server(80); + +static std::string htmlEncode(std::string data) { + const char *p = data.c_str(); + std::string rv = ""; + while(p && *p) { + char escapeChar = *p++; + switch(escapeChar) { + case '&': rv += "&"; break; + case '<': rv += "<"; break; + case '>': rv += ">"; break; + case '"': rv += """; break; + case '\'': rv += "'"; break; + case '/': rv += "/"; break; + default: rv += escapeChar; break; + } + } + return rv; +} + +void handleRoot() { + String rv; + rv += ""; + rv += ""; + rv += "Very simple file server"; + rv += ""; + rv += "

    Very simple file server

    "; + rv += "

    This is a very simple file server to demonstrate the use of POST forms.

    "; + rv += "

    List existing files

    "; + rv += "

    See /public to list existing files and retrieve or edit them.

    "; + rv += "

    Upload new file

    "; + rv += "

    This form allows you to upload files (text, jpg and png supported best). It demonstrates multipart/form-data.

    "; + rv += "
    "; + rv += "file:
    "; + rv += ""; + rv += "
    "; + rv += ""; + rv += ""; + server.send(200, "text/html", rv); +} + +void handleFormEdit() { + if (!server.authenticate("admin", "admin")) return server.requestAuthentication(); + bool hasFilename = server.hasArg("filename");; + String filename = server.arg("filename"); + String pathname = String("/public/") + filename; + if (server.hasArg("content") ){ + // Content has been edited. Save. + File file = SPIFFS.open(pathname.c_str(), "w"); + String content = server.arg("content"); + file.write((uint8_t *)content.c_str(), content.length()); + file.close(); + } + String content = server.arg("content"); + String rv; + rv += "Edit File\n"; + File file = SPIFFS.open(pathname.c_str()); + if (!hasFilename) { + rv += "

    No filename specified.

    \n"; + } else if (!file.available()) { + rv += "

    File not found:"; + rv += pathname; + rv += "

    \n"; + } else { + rv += "

    Edit content of "; + rv += pathname; + rv += "

    \n"; + rv += "
    \n"; + rv += "\n"; + rv += "
    "; + rv += ""; + rv += "
    "; + } + rv += ""; + server.send(200, "text/html", rv); +} + +void handleFormUpload() { + Serial.println("handleUpload() called"); + server.send(200); +} + +File fsUploadFile; + +void handleFormUploadFile() { + Serial.println("handleUploadFile() called"); + HTTPUpload& upload = server.upload(); + if(upload.status == UPLOAD_FILE_START){ + String filename = String("/public/") + upload.filename; + Serial.printf("upload filename=%s\n", filename.c_str()); + Serial.print("handleFileUpload Name: "); Serial.println(filename); + fsUploadFile = SPIFFS.open(filename, "w"); // Open the file for writing in SPIFFS (create if it doesn't exist) + } else if(upload.status == UPLOAD_FILE_WRITE){ + Serial.printf("uploaded %d bytes\n", upload.currentSize); + if(fsUploadFile) + fsUploadFile.write(upload.buf, upload.currentSize); // Write the received bytes to the file + } else if(upload.status == UPLOAD_FILE_END){ + Serial.printf("upload total %d bytes\n", upload.totalSize); + if(fsUploadFile) { // If the file was successfully created + fsUploadFile.close(); // Close the file again + Serial.print("handleFileUpload Size: "); Serial.println(upload.totalSize); + server.sendHeader("Location","/public"); // Redirect the client to the success page + server.send(303); + } else { + server.send(500, "text/plain", "500: couldn't create file"); + } + server.send(200, "text/plain", "OK"); + } +} + +void handleDirectory() { + String rv; + rv += "File Listing\n"; + File d = SPIFFS.open("/public"); + if (!d.isDirectory()) { + rv += "

    No files found.

    \n"; + } else { + rv += "

    File Listing

    \n"; + rv += "
      \n"; + File f = d.openNextFile(); + while (f) { + std::string pathname(f.name()); + std::string filename = pathname.substr(8); // Remove /public/ + rv += "
    • "; + rv += String(filename.c_str()); + rv += ""; + if (pathname.rfind(".txt") != std::string::npos) { + rv += " [edit]"; + } + rv += "
    • "; + f = d.openNextFile(); + } + rv += "
    "; + } + rv += ""; + server.send(200, "text/html", rv); +} + +void handleNotFound() { + String message = "File Not Found\n\n"; + message += "URI: "; + message += server.uri(); + message += "\nMethod: "; + message += (server.method() == HTTP_GET) ? "GET" : "POST"; + message += "\nArguments: "; + message += server.args(); + message += "\n"; + for (uint8_t i = 0; i < server.args(); i++) { + message += " " + server.argName(i) + ": " + server.arg(i) + "\n"; + } + server.send(404, "text/plain", message); +} + +void setup(void) { + Serial.begin(115200); + WiFi.mode(WIFI_STA); + WiFi.begin(ssid, password); + Serial.println(""); + + // Wait for connection + while (WiFi.status() != WL_CONNECTED) { + delay(500); + Serial.print("."); + } + Serial.println(""); + Serial.print("Connected to "); + Serial.println(ssid); + Serial.print("IP address: "); + Serial.println(WiFi.localIP()); + + if (MDNS.begin("esp32")) { + Serial.println("MDNS responder started"); + } + // Setup filesystem + if (!SPIFFS.begin(true)) Serial.println("Mounting SPIFFS failed"); + + server.on("/", handleRoot); + server.on("/upload", HTTP_POST, handleFormUpload, handleFormUploadFile); + server.on("/edit", HTTP_GET, handleFormEdit); + server.on("/edit", HTTP_POST, handleFormEdit); + // Note: /public (without trailing /) gives directory listing, but /public/... retrieves static files. + server.on("/public", HTTP_GET, handleDirectory); + server.serveStatic("/public/", SPIFFS, "/public/"); + + server.onNotFound(handleNotFound); + + server.begin(); + Serial.println("HTTP server started"); +} + +void loop(void) { + server.handleClient(); +} diff --git a/examples/FormServer/mainFormServer.cpp b/examples/FormServer/mainFormServer.cpp deleted file mode 100644 index 572d8da..0000000 --- a/examples/FormServer/mainFormServer.cpp +++ /dev/null @@ -1,224 +0,0 @@ -#include -#include -#include -#include -#include -#ifdef USE_DEFAULT_WEBSERVER -#include -typedef WebServer ESPWebServer; -#else -#include -#endif - -const char* ssid = "........"; -const char* password = "........"; - -ESPWebServer server(80); - -static std::string htmlEncode(std::string data) { - const char *p = data.c_str(); - std::string rv = ""; - while(p && *p) { - char escapeChar = *p++; - switch(escapeChar) { - case '&': rv += "&"; break; - case '<': rv += "<"; break; - case '>': rv += ">"; break; - case '"': rv += """; break; - case '\'': rv += "'"; break; - case '/': rv += "/"; break; - default: rv += escapeChar; break; - } - } - return rv; -} - -void handleRoot() { - String rv; - rv += ""; - rv += ""; - rv += "Very simple file server"; - rv += ""; - rv += "

    Very simple file server

    "; - rv += "

    This is a very simple file server to demonstrate the use of POST forms.

    "; - rv += "

    List existing files

    "; - rv += "

    See /public to list existing files and retrieve or edit them.

    "; - rv += "

    Upload new file

    "; - rv += "

    This form allows you to upload files (text, jpg and png supported best). It demonstrates multipart/form-data.

    "; - rv += "
    "; - rv += "file:
    "; - rv += ""; - rv += "
    "; - rv += ""; - rv += ""; - server.send(200, "text/html", rv); -} - -void handleFormEdit() { - if (!server.authenticate("admin", "admin")) return server.requestAuthentication(); - bool hasFilename = server.hasArg("filename");; - String filename = server.arg("filename"); - String pathname = String("/public/") + filename; - if (server.hasArg("content") ){ - // Content has been edited. Save. - File file = SPIFFS.open(pathname.c_str(), "w"); - String content = server.arg("content"); - file.write((uint8_t *)content.c_str(), content.length()); - file.close(); - } - String content = server.arg("content"); - String rv; - rv += "Edit File\n"; - File file = SPIFFS.open(pathname.c_str()); - if (!hasFilename) { - rv += "

    No filename specified.

    \n"; - } else if (!file.available()) { - rv += "

    File not found:"; - rv += pathname; - rv += "

    \n"; - } else { - rv += "

    Edit content of "; - rv += pathname; - rv += "

    \n"; - rv += "
    \n"; - rv += "\n"; - rv += "
    "; - rv += ""; - rv += "
    "; - } - rv += ""; - server.send(200, "text/html", rv); -} - -void handleFormUpload() { - Serial.println("handleUpload() called"); - server.send(200); -} - -File fsUploadFile; - -void handleFormUploadFile() { - Serial.println("handleUploadFile() called"); - HTTPUpload& upload = server.upload(); - if(upload.status == UPLOAD_FILE_START){ - String filename = String("/public/") + upload.filename; - Serial.printf("upload filename=%s\n", filename.c_str()); - Serial.print("handleFileUpload Name: "); Serial.println(filename); - fsUploadFile = SPIFFS.open(filename, "w"); // Open the file for writing in SPIFFS (create if it doesn't exist) - } else if(upload.status == UPLOAD_FILE_WRITE){ - Serial.printf("uploaded %d bytes\n", upload.currentSize); - if(fsUploadFile) - fsUploadFile.write(upload.buf, upload.currentSize); // Write the received bytes to the file - } else if(upload.status == UPLOAD_FILE_END){ - Serial.printf("upload total %d bytes\n", upload.totalSize); - if(fsUploadFile) { // If the file was successfully created - fsUploadFile.close(); // Close the file again - Serial.print("handleFileUpload Size: "); Serial.println(upload.totalSize); - server.sendHeader("Location","/public"); // Redirect the client to the success page - server.send(303); - } else { - server.send(500, "text/plain", "500: couldn't create file"); - } - server.send(200, "text/plain", "OK"); - } -} - -void handleDirectory() { - String rv; - rv += "File Listing\n"; - File d = SPIFFS.open("/public"); - if (!d.isDirectory()) { - rv += "

    No files found.

    \n"; - } else { - rv += "

    File Listing

    \n"; - rv += "
      \n"; - File f = d.openNextFile(); - while (f) { - std::string pathname(f.name()); - std::string filename = pathname.substr(8); // Remove /public/ - rv += "
    • "; - rv += String(filename.c_str()); - rv += ""; - if (pathname.rfind(".txt") != std::string::npos) { - rv += " [edit]"; - } - rv += "
    • "; - f = d.openNextFile(); - } - rv += "
    "; - } - rv += ""; - server.send(200, "text/html", rv); -} - -void handleNotFound() { - String message = "File Not Found\n\n"; - message += "URI: "; - message += server.uri(); - message += "\nMethod: "; - message += (server.method() == HTTP_GET) ? "GET" : "POST"; - message += "\nArguments: "; - message += server.args(); - message += "\n"; - for (uint8_t i = 0; i < server.args(); i++) { - message += " " + server.argName(i) + ": " + server.arg(i) + "\n"; - } - server.send(404, "text/plain", message); -} - -void setup(void) { - Serial.begin(115200); - WiFi.mode(WIFI_STA); - WiFi.begin(ssid, password); - Serial.println(""); - - // Wait for connection - while (WiFi.status() != WL_CONNECTED) { - delay(500); - Serial.print("."); - } - Serial.println(""); - Serial.print("Connected to "); - Serial.println(ssid); - Serial.print("IP address: "); - Serial.println(WiFi.localIP()); - - if (MDNS.begin("esp32")) { - Serial.println("MDNS responder started"); - } - // Setup filesystem - if (!SPIFFS.begin(true)) Serial.println("Mounting SPIFFS failed"); - - server.on("/", handleRoot); - server.on("/upload", HTTP_POST, handleFormUpload, handleFormUploadFile); - server.on("/edit", HTTP_GET, handleFormEdit); - server.on("/edit", HTTP_POST, handleFormEdit); - // Note: /public (without trailing /) gives directory listing, but /public/... retrieves static files. - server.on("/public", HTTP_GET, handleDirectory); - server.serveStatic("/public/", SPIFFS, "/public/"); - - server.onNotFound(handleNotFound); - - server.begin(); - Serial.println("HTTP server started"); -} - -void loop(void) { - server.handleClient(); -} diff --git a/examples/HelloServer/HelloServer.ino b/examples/HelloServer/HelloServer.ino index 6461c9a..3c9a881 100644 --- a/examples/HelloServer/HelloServer.ino +++ b/examples/HelloServer/HelloServer.ino @@ -3,6 +3,161 @@ #include #ifdef USE_DEFAULT_WEBSERVER #include +typedef WebServer ESPWebServer; #else #include #endif + +const char* ssid = "........"; +const char* password = "........"; + +ESPWebServer server(80); + +const int led = 13; + +void handleRoot() { + digitalWrite(led, 1); + server.send(200, "text/plain", "hello from esp32! See /form and /inline too!"); + digitalWrite(led, 0); +} + +void handleForm() { + String line = server.arg("line"); + Serial.print("line: "); + Serial.println(line); + String multi = server.arg("multi"); + Serial.print("multi: "); + Serial.println(multi); + String file = server.arg("file"); + Serial.print("file: "); + Serial.println(file); + line.toLowerCase(); + multi.toUpperCase(); + String rv; + rv = "Test Form"; + rv += "

    Form using GET

    "; + rv += "
    "; + rv += "Single line:

    "; + rv += "Multi line:

    "; + rv += "File:

    "; + rv += ""; + rv += "
    "; + rv += "

    Form using POST urlencoded

    "; + rv += "
    "; + rv += "Single line:

    "; + rv += "Multi line:

    "; + rv += "File:

    "; + rv += ""; + rv += "
    "; + rv += "

    Form using POST with multipart

    "; + rv += "
    "; + rv += "Single line:

    "; + rv += "Multi line:

    "; + rv += "File:

    "; + rv += ""; + rv += "
    "; + server.send(200, "text/html", rv); +} + +void handleUpload() { + Serial.println("handleUpload() called"); + String line = server.arg("line"); + Serial.print("line: "); + Serial.println(line); + String multi = server.arg("multi"); + Serial.print("multi: "); + Serial.println(multi); + server.send(200); +} + +void handleUploadFile() { + Serial.println("handleUploadFile() called"); + HTTPUpload& upload = server.upload(); + if(upload.status == UPLOAD_FILE_START){ + String filename = upload.filename; + Serial.printf("upload filename=%s\n", filename.c_str()); +#if 0 + if(!filename.startsWith("/")) filename = "/"+filename; + Serial.print("handleFileUpload Name: "); Serial.println(filename); + fsUploadFile = SPIFFS.open(filename, "w"); // Open the file for writing in SPIFFS (create if it doesn't exist) + filename = String(); +#endif + } else if(upload.status == UPLOAD_FILE_WRITE){ + Serial.printf("uploaded %d bytes\n", upload.currentSize); +#if 0 + if(fsUploadFile) + fsUploadFile.write(upload.buf, upload.currentSize); // Write the received bytes to the file +#endif + } else if(upload.status == UPLOAD_FILE_END){ + Serial.printf("upload total %d bytes\n", upload.totalSize); +#if 0 + if(fsUploadFile) { // If the file was successfully created + fsUploadFile.close(); // Close the file again + Serial.print("handleFileUpload Size: "); Serial.println(upload.totalSize); + server.sendHeader("Location","/success.html"); // Redirect the client to the success page + server.send(303); + } else { + server.send(500, "text/plain", "500: couldn't create file"); + } +#endif + server.send(200, "text/plain", "OK"); + } +} + +void handleNotFound() { + digitalWrite(led, 1); + String message = "File Not Found\n\n"; + message += "URI: "; + message += server.uri(); + message += "\nMethod: "; + message += (server.method() == HTTP_GET) ? "GET" : "POST"; + message += "\nArguments: "; + message += server.args(); + message += "\n"; + for (uint8_t i = 0; i < server.args(); i++) { + message += " " + server.argName(i) + ": " + server.arg(i) + "\n"; + } + server.send(404, "text/plain", message); + digitalWrite(led, 0); +} + +void setup(void) { + pinMode(led, OUTPUT); + digitalWrite(led, 0); + Serial.begin(115200); + WiFi.mode(WIFI_STA); + WiFi.begin(ssid, password); + Serial.println(""); + + // Wait for connection + while (WiFi.status() != WL_CONNECTED) { + delay(500); + Serial.print("."); + } + Serial.println(""); + Serial.print("Connected to "); + Serial.println(ssid); + Serial.print("IP address: "); + Serial.println(WiFi.localIP()); + + if (MDNS.begin("esp32")) { + Serial.println("MDNS responder started"); + } + + server.on("/", handleRoot); + server.on("/form", handleForm); + server.on("/form", HTTP_POST, handleForm); + server.on("/upload", HTTP_POST, handleUpload, handleUploadFile); + server.on("/inline", []() { + server.send(200, "text/plain", "this works as well"); + }); + + server.onNotFound(handleNotFound); + + server.begin(); + Serial.println("HTTP server started"); +} + +void loop(void) { + server.handleClient(); +} diff --git a/examples/HelloServer/mainHelloServer.cpp b/examples/HelloServer/mainHelloServer.cpp deleted file mode 100644 index 5e96469..0000000 --- a/examples/HelloServer/mainHelloServer.cpp +++ /dev/null @@ -1,164 +0,0 @@ -#include -#include -#include -#include -#ifdef USE_DEFAULT_WEBSERVER -#include -typedef WebServer ESPWebServer; -#else -#include -#endif - -const char* ssid = "........"; -const char* password = "........"; - -ESPWebServer server(80); - -const int led = 13; - -void handleRoot() { - digitalWrite(led, 1); - server.send(200, "text/plain", "hello from esp32! See /form and /inline too!"); - digitalWrite(led, 0); -} - -void handleForm() { - String line = server.arg("line"); - Serial.print("line: "); - Serial.println(line); - String multi = server.arg("multi"); - Serial.print("multi: "); - Serial.println(multi); - String file = server.arg("file"); - Serial.print("file: "); - Serial.println(file); - line.toLowerCase(); - multi.toUpperCase(); - String rv; - rv = "Test Form"; - rv += "

    Form using GET

    "; - rv += "
    "; - rv += "Single line:

    "; - rv += "Multi line:

    "; - rv += "File:

    "; - rv += ""; - rv += "
    "; - rv += "

    Form using POST urlencoded

    "; - rv += "
    "; - rv += "Single line:

    "; - rv += "Multi line:

    "; - rv += "File:

    "; - rv += ""; - rv += "
    "; - rv += "

    Form using POST with multipart

    "; - rv += "
    "; - rv += "Single line:

    "; - rv += "Multi line:

    "; - rv += "File:

    "; - rv += ""; - rv += "
    "; - server.send(200, "text/html", rv); -} - -void handleUpload() { - Serial.println("handleUpload() called"); - String line = server.arg("line"); - Serial.print("line: "); - Serial.println(line); - String multi = server.arg("multi"); - Serial.print("multi: "); - Serial.println(multi); - server.send(200); -} - -void handleUploadFile() { - Serial.println("handleUploadFile() called"); - HTTPUpload& upload = server.upload(); - if(upload.status == UPLOAD_FILE_START){ - String filename = upload.filename; - Serial.printf("upload filename=%s\n", filename.c_str()); -#if 0 - if(!filename.startsWith("/")) filename = "/"+filename; - Serial.print("handleFileUpload Name: "); Serial.println(filename); - fsUploadFile = SPIFFS.open(filename, "w"); // Open the file for writing in SPIFFS (create if it doesn't exist) - filename = String(); -#endif - } else if(upload.status == UPLOAD_FILE_WRITE){ - Serial.printf("uploaded %d bytes\n", upload.currentSize); -#if 0 - if(fsUploadFile) - fsUploadFile.write(upload.buf, upload.currentSize); // Write the received bytes to the file -#endif - } else if(upload.status == UPLOAD_FILE_END){ - Serial.printf("upload total %d bytes\n", upload.totalSize); -#if 0 - if(fsUploadFile) { // If the file was successfully created - fsUploadFile.close(); // Close the file again - Serial.print("handleFileUpload Size: "); Serial.println(upload.totalSize); - server.sendHeader("Location","/success.html"); // Redirect the client to the success page - server.send(303); - } else { - server.send(500, "text/plain", "500: couldn't create file"); - } -#endif - server.send(200, "text/plain", "OK"); - } -} - -void handleNotFound() { - digitalWrite(led, 1); - String message = "File Not Found\n\n"; - message += "URI: "; - message += server.uri(); - message += "\nMethod: "; - message += (server.method() == HTTP_GET) ? "GET" : "POST"; - message += "\nArguments: "; - message += server.args(); - message += "\n"; - for (uint8_t i = 0; i < server.args(); i++) { - message += " " + server.argName(i) + ": " + server.arg(i) + "\n"; - } - server.send(404, "text/plain", message); - digitalWrite(led, 0); -} - -void setup(void) { - pinMode(led, OUTPUT); - digitalWrite(led, 0); - Serial.begin(115200); - WiFi.mode(WIFI_STA); - WiFi.begin(ssid, password); - Serial.println(""); - - // Wait for connection - while (WiFi.status() != WL_CONNECTED) { - delay(500); - Serial.print("."); - } - Serial.println(""); - Serial.print("Connected to "); - Serial.println(ssid); - Serial.print("IP address: "); - Serial.println(WiFi.localIP()); - - if (MDNS.begin("esp32")) { - Serial.println("MDNS responder started"); - } - - server.on("/", handleRoot); - server.on("/form", handleForm); - server.on("/form", HTTP_POST, handleForm); - server.on("/upload", HTTP_POST, handleUpload, handleUploadFile); - server.on("/inline", []() { - server.send(200, "text/plain", "this works as well"); - }); - - server.onNotFound(handleNotFound); - - server.begin(); - Serial.println("HTTP server started"); -} - -void loop(void) { - server.handleClient(); -} From b6b556952b79e5ee30b3bbf2cce0cca22fb37200 Mon Sep 17 00:00:00 2001 From: Jack Jansen Date: Thu, 9 Apr 2020 00:42:53 +0200 Subject: [PATCH 43/54] Copy key and cert to malloc()ed memory. Needed for persistency, but also because PROGMEM key/cert are not always supported by esp32_https_server. --- src/ESPWebServerSecure.cpp | 18 +++++++++++++++--- src/ESPWebServerSecure.hpp | 2 ++ 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/src/ESPWebServerSecure.cpp b/src/ESPWebServerSecure.cpp index 04db490..0aec7a9 100644 --- a/src/ESPWebServerSecure.cpp +++ b/src/ESPWebServerSecure.cpp @@ -4,7 +4,9 @@ ESPWebServerSecure::ESPWebServerSecure(IPAddress addr, int port) : ESPWebServer(new httpsserver::HTTPSServer(&_sslCert, port, 4, addr)), _underlyingServer(this), - _sslCert() + _sslCert(), + keyStore(NULL), + certStore(NULL) {} ESPWebServerSecure::ESPWebServerSecure(int port) @@ -14,8 +16,18 @@ ESPWebServerSecure::ESPWebServerSecure(int port) {} void ESPWebServerSecure::setServerKeyAndCert(const uint8_t *key, int keyLen, const uint8_t *cert, int certLen) { - _sslCert.setPK((unsigned char *)key, keyLen); - _sslCert.setCert((unsigned char *)cert, certLen); + if (keyStore) free(keyStore); + if (certStore) free(certStore); + keyStore = (uint8_t *)malloc(keyLen); + certStore = (uint8_t *)malloc(certLen); + if (keyStore == NULL || certStore == NULL) { + HTTPS_LOGE("Out of memory for key and cert"); + return; + } + memcpy_P(keyStore, key, keyLen); + memcpy_P(certStore, cert, certLen); + _sslCert.setPK(keyStore, keyLen); + _sslCert.setCert(certStore, certLen); } void ESPWebServerSecure::setServerKeyAndCert_P(const uint8_t *key, int keyLen, const uint8_t *cert, int certLen) { diff --git a/src/ESPWebServerSecure.hpp b/src/ESPWebServerSecure.hpp index 6299c1a..01ced28 100644 --- a/src/ESPWebServerSecure.hpp +++ b/src/ESPWebServerSecure.hpp @@ -31,6 +31,8 @@ class ESPWebServerSecure : public ESPWebServer { protected: ESPWebServerUnderlyingServer _underlyingServer; httpsserver::SSLCert _sslCert; + uint8_t* keyStore; + uint8_t* certStore; }; #endif //ESPWEBSERVERSECURE_H \ No newline at end of file From 6b7af09d362d4715a763931033f196608a7cfb30 Mon Sep 17 00:00:00 2001 From: Jack Jansen Date: Thu, 9 Apr 2020 01:03:49 +0200 Subject: [PATCH 44/54] Initialize keyStore and certStore in all constructors --- src/ESPWebServerSecure.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/ESPWebServerSecure.cpp b/src/ESPWebServerSecure.cpp index 0aec7a9..bdcc6b8 100644 --- a/src/ESPWebServerSecure.cpp +++ b/src/ESPWebServerSecure.cpp @@ -12,7 +12,9 @@ ESPWebServerSecure::ESPWebServerSecure(IPAddress addr, int port) ESPWebServerSecure::ESPWebServerSecure(int port) : ESPWebServer(new httpsserver::HTTPSServer(&_sslCert, port, 4)), _underlyingServer(this), - _sslCert() + _sslCert(), + keyStore(NULL), + certStore(NULL) {} void ESPWebServerSecure::setServerKeyAndCert(const uint8_t *key, int keyLen, const uint8_t *cert, int certLen) { From e2efba8890c8cb298c9f04031fa8477ea2b583ca Mon Sep 17 00:00:00 2001 From: Jack Jansen Date: Fri, 10 Apr 2020 00:54:06 +0200 Subject: [PATCH 45/54] Revert "Initialize keyStore and certStore in all constructors" This reverts commit 6b7af09d362d4715a763931033f196608a7cfb30. --- src/ESPWebServerSecure.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/ESPWebServerSecure.cpp b/src/ESPWebServerSecure.cpp index bdcc6b8..0aec7a9 100644 --- a/src/ESPWebServerSecure.cpp +++ b/src/ESPWebServerSecure.cpp @@ -12,9 +12,7 @@ ESPWebServerSecure::ESPWebServerSecure(IPAddress addr, int port) ESPWebServerSecure::ESPWebServerSecure(int port) : ESPWebServer(new httpsserver::HTTPSServer(&_sslCert, port, 4)), _underlyingServer(this), - _sslCert(), - keyStore(NULL), - certStore(NULL) + _sslCert() {} void ESPWebServerSecure::setServerKeyAndCert(const uint8_t *key, int keyLen, const uint8_t *cert, int certLen) { From 5e2424b70a3c0aa324d2df5a1c777537eb1cd513 Mon Sep 17 00:00:00 2001 From: Jack Jansen Date: Fri, 10 Apr 2020 00:54:17 +0200 Subject: [PATCH 46/54] Revert "Copy key and cert to malloc()ed memory. Needed for persistency, but also because PROGMEM key/cert are not always supported by esp32_https_server." This reverts commit b6b556952b79e5ee30b3bbf2cce0cca22fb37200. --- src/ESPWebServerSecure.cpp | 18 +++--------------- src/ESPWebServerSecure.hpp | 2 -- 2 files changed, 3 insertions(+), 17 deletions(-) diff --git a/src/ESPWebServerSecure.cpp b/src/ESPWebServerSecure.cpp index 0aec7a9..04db490 100644 --- a/src/ESPWebServerSecure.cpp +++ b/src/ESPWebServerSecure.cpp @@ -4,9 +4,7 @@ ESPWebServerSecure::ESPWebServerSecure(IPAddress addr, int port) : ESPWebServer(new httpsserver::HTTPSServer(&_sslCert, port, 4, addr)), _underlyingServer(this), - _sslCert(), - keyStore(NULL), - certStore(NULL) + _sslCert() {} ESPWebServerSecure::ESPWebServerSecure(int port) @@ -16,18 +14,8 @@ ESPWebServerSecure::ESPWebServerSecure(int port) {} void ESPWebServerSecure::setServerKeyAndCert(const uint8_t *key, int keyLen, const uint8_t *cert, int certLen) { - if (keyStore) free(keyStore); - if (certStore) free(certStore); - keyStore = (uint8_t *)malloc(keyLen); - certStore = (uint8_t *)malloc(certLen); - if (keyStore == NULL || certStore == NULL) { - HTTPS_LOGE("Out of memory for key and cert"); - return; - } - memcpy_P(keyStore, key, keyLen); - memcpy_P(certStore, cert, certLen); - _sslCert.setPK(keyStore, keyLen); - _sslCert.setCert(certStore, certLen); + _sslCert.setPK((unsigned char *)key, keyLen); + _sslCert.setCert((unsigned char *)cert, certLen); } void ESPWebServerSecure::setServerKeyAndCert_P(const uint8_t *key, int keyLen, const uint8_t *cert, int certLen) { diff --git a/src/ESPWebServerSecure.hpp b/src/ESPWebServerSecure.hpp index 01ced28..6299c1a 100644 --- a/src/ESPWebServerSecure.hpp +++ b/src/ESPWebServerSecure.hpp @@ -31,8 +31,6 @@ class ESPWebServerSecure : public ESPWebServer { protected: ESPWebServerUnderlyingServer _underlyingServer; httpsserver::SSLCert _sslCert; - uint8_t* keyStore; - uint8_t* certStore; }; #endif //ESPWEBSERVERSECURE_H \ No newline at end of file From cdbb7188e66abe896ffc65faecbdfa6f7f3d4467 Mon Sep 17 00:00:00 2001 From: Jack Jansen Date: Sat, 11 Apr 2020 02:04:23 +0200 Subject: [PATCH 47/54] Rationalized example to only show that three methods of form submission are identical --- examples/HelloServer/HelloServer.ino | 51 ++-------------------------- 1 file changed, 2 insertions(+), 49 deletions(-) diff --git a/examples/HelloServer/HelloServer.ino b/examples/HelloServer/HelloServer.ino index 3c9a881..74994cb 100644 --- a/examples/HelloServer/HelloServer.ino +++ b/examples/HelloServer/HelloServer.ino @@ -35,74 +35,28 @@ void handleForm() { multi.toUpperCase(); String rv; rv = "Test Form"; + rv += "

    Single line will be converted to lowercase, multi line to uppercase. You can submit the form with three different methods.

    "; rv += "

    Form using GET

    "; rv += "
    "; rv += "Single line:

    "; rv += "Multi line:

    "; - rv += "File:

    "; rv += ""; rv += "
    "; rv += "

    Form using POST urlencoded

    "; rv += "
    "; rv += "Single line:

    "; rv += "Multi line:

    "; - rv += "File:

    "; rv += ""; rv += "
    "; rv += "

    Form using POST with multipart

    "; - rv += "
    "; + rv += ""; rv += "Single line:

    "; rv += "Multi line:

    "; - rv += "File:

    "; rv += ""; rv += "
    "; server.send(200, "text/html", rv); } -void handleUpload() { - Serial.println("handleUpload() called"); - String line = server.arg("line"); - Serial.print("line: "); - Serial.println(line); - String multi = server.arg("multi"); - Serial.print("multi: "); - Serial.println(multi); - server.send(200); -} - -void handleUploadFile() { - Serial.println("handleUploadFile() called"); - HTTPUpload& upload = server.upload(); - if(upload.status == UPLOAD_FILE_START){ - String filename = upload.filename; - Serial.printf("upload filename=%s\n", filename.c_str()); -#if 0 - if(!filename.startsWith("/")) filename = "/"+filename; - Serial.print("handleFileUpload Name: "); Serial.println(filename); - fsUploadFile = SPIFFS.open(filename, "w"); // Open the file for writing in SPIFFS (create if it doesn't exist) - filename = String(); -#endif - } else if(upload.status == UPLOAD_FILE_WRITE){ - Serial.printf("uploaded %d bytes\n", upload.currentSize); -#if 0 - if(fsUploadFile) - fsUploadFile.write(upload.buf, upload.currentSize); // Write the received bytes to the file -#endif - } else if(upload.status == UPLOAD_FILE_END){ - Serial.printf("upload total %d bytes\n", upload.totalSize); -#if 0 - if(fsUploadFile) { // If the file was successfully created - fsUploadFile.close(); // Close the file again - Serial.print("handleFileUpload Size: "); Serial.println(upload.totalSize); - server.sendHeader("Location","/success.html"); // Redirect the client to the success page - server.send(303); - } else { - server.send(500, "text/plain", "500: couldn't create file"); - } -#endif - server.send(200, "text/plain", "OK"); - } -} void handleNotFound() { digitalWrite(led, 1); @@ -147,7 +101,6 @@ void setup(void) { server.on("/", handleRoot); server.on("/form", handleForm); server.on("/form", HTTP_POST, handleForm); - server.on("/upload", HTTP_POST, handleUpload, handleUploadFile); server.on("/inline", []() { server.send(200, "text/plain", "this works as well"); }); From 31d361f67c003537459c3a912cfcc68d62f3b41f Mon Sep 17 00:00:00 2001 From: Jack Jansen Date: Sun, 12 Apr 2020 00:37:37 +0200 Subject: [PATCH 48/54] Remove outdated file parameter Co-Authored-By: Frank Hessel --- examples/HelloServer/HelloServer.ino | 3 --- 1 file changed, 3 deletions(-) diff --git a/examples/HelloServer/HelloServer.ino b/examples/HelloServer/HelloServer.ino index 74994cb..339e71f 100644 --- a/examples/HelloServer/HelloServer.ino +++ b/examples/HelloServer/HelloServer.ino @@ -28,9 +28,6 @@ void handleForm() { String multi = server.arg("multi"); Serial.print("multi: "); Serial.println(multi); - String file = server.arg("file"); - Serial.print("file: "); - Serial.println(file); line.toLowerCase(); multi.toUpperCase(); String rv; From 689a089adfbad2025f9977bbb419415f811a280b Mon Sep 17 00:00:00 2001 From: Jack Jansen Date: Sun, 12 Apr 2020 00:41:30 +0200 Subject: [PATCH 49/54] Removed copy/paste turd --- examples/HelloServer/HelloServer.ino | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/HelloServer/HelloServer.ino b/examples/HelloServer/HelloServer.ino index 339e71f..ceefd72 100644 --- a/examples/HelloServer/HelloServer.ino +++ b/examples/HelloServer/HelloServer.ino @@ -38,13 +38,13 @@ void handleForm() { rv += "Single line:

    "; rv += "Multi line:

    "; rv += ""; - rv += ""; + rv += ""; rv += "

    Form using POST urlencoded

    "; rv += "
    "; rv += "Single line:

    "; rv += "Multi line:

    "; rv += ""; - rv += "
    "; + rv += ""; rv += "

    Form using POST with multipart

    "; rv += "
    "; rv += "Single line:

    "; From cead0c137c715ab51ea282d0b042138bcd8795f4 Mon Sep 17 00:00:00 2001 From: Jack Jansen Date: Sun, 12 Apr 2020 00:43:54 +0200 Subject: [PATCH 50/54] No need to refer to esp32_https_server by GitHub url anymore Co-Authored-By: Frank Hessel --- platformio.ini | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/platformio.ini b/platformio.ini index b8dd49e..e764ded 100644 --- a/platformio.ini +++ b/platformio.ini @@ -6,7 +6,7 @@ framework = arduino platform = espressif32@>=1.11 board = lolin32 lib_ldf_mode = deep+ -lib_deps = https://github.com/fhessel/esp32_https_server.git +lib_deps = esp32_https_server@~1.0.0 build_flags = -DHTTPS_LOGLEVEL=4 -DHTTPS_REQUEST_MAX_REQUEST_LENGTH=800 src_filter = +<*> +<../examples/FormServer/> debug_tool = minimodule @@ -47,4 +47,4 @@ lib_deps = https://github.com/fhessel/esp32_https_server.git build_flags = -DHTTPS_LOGLEVEL=4 -DHTTPS_REQUEST_MAX_REQUEST_LENGTH=800 src_filter = +<*> +<../examples/HelloServer/> monitor_speed = 115200 -upload_speed = 115200 \ No newline at end of file +upload_speed = 115200 From c49ceb17f7e636681b85a3428bad5d9fd96a47cf Mon Sep 17 00:00:00 2001 From: Jack Jansen Date: Sun, 12 Apr 2020 00:44:08 +0200 Subject: [PATCH 51/54] No need to refer to esp32_https_server by GitHub url anymore Co-Authored-By: Frank Hessel --- platformio.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platformio.ini b/platformio.ini index e764ded..dff920f 100644 --- a/platformio.ini +++ b/platformio.ini @@ -19,7 +19,7 @@ framework = arduino platform = espressif32@>=1.11 board = lolin32 lib_ldf_mode = deep+ -lib_deps = https://github.com/fhessel/esp32_https_server.git +lib_deps = esp32_https_server@~1.0.0 build_flags = -DHTTPS_LOGLEVEL=4 -DHTTPS_REQUEST_MAX_REQUEST_LENGTH=800 src_filter = +<*> +<../examples/FormServer/> monitor_speed = 115200 From 2c2b82229a8aa5133d159de16ccc76d2332dc6f4 Mon Sep 17 00:00:00 2001 From: Jack Jansen Date: Sun, 12 Apr 2020 00:44:29 +0200 Subject: [PATCH 52/54] No need to refer to esp32_https_server by GitHub url anymore Co-Authored-By: Frank Hessel --- platformio.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platformio.ini b/platformio.ini index dff920f..cea1eb6 100644 --- a/platformio.ini +++ b/platformio.ini @@ -30,7 +30,7 @@ framework = arduino platform = espressif32@>=1.11 board = lolin32 lib_ldf_mode = deep+ -lib_deps = https://github.com/fhessel/esp32_https_server.git +lib_deps = esp32_https_server@~1.0.0 build_flags = -DHTTPS_LOGLEVEL=4 -DHTTPS_REQUEST_MAX_REQUEST_LENGTH=800 src_filter = +<*> +<../examples/HelloServer/> debug_tool = minimodule From c571ce14bf67fad9abe8aa2319b00a686921d08d Mon Sep 17 00:00:00 2001 From: Jack Jansen Date: Sun, 12 Apr 2020 00:44:42 +0200 Subject: [PATCH 53/54] No need to refer to esp32_https_server by GitHub url anymore Co-Authored-By: Frank Hessel --- platformio.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platformio.ini b/platformio.ini index cea1eb6..2ad1e78 100644 --- a/platformio.ini +++ b/platformio.ini @@ -43,7 +43,7 @@ framework = arduino platform = espressif32@>=1.11 board = lolin32 lib_ldf_mode = deep+ -lib_deps = https://github.com/fhessel/esp32_https_server.git +lib_deps = esp32_https_server@~1.0.0 build_flags = -DHTTPS_LOGLEVEL=4 -DHTTPS_REQUEST_MAX_REQUEST_LENGTH=800 src_filter = +<*> +<../examples/HelloServer/> monitor_speed = 115200 From ce11e22bffe589101d44ab9c54e9ca4c71899fae Mon Sep 17 00:00:00 2001 From: Jack Jansen Date: Sun, 12 Apr 2020 00:45:19 +0200 Subject: [PATCH 54/54] esp32_https_server is now version 1.0.0 Co-Authored-By: Frank Hessel --- library.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library.json b/library.json index 8d2be79..ebfb9da 100644 --- a/library.json +++ b/library.json @@ -22,7 +22,7 @@ "dependencies": [ { "name": "esp32_https_server", - "version": "https://github.com/fhessel/esp32_https_server.git" + "version": "~1.0.0" } ], "license": "MIT",