From 50eb6d9ff241e744b0344daaf04334b205ca3dd3 Mon Sep 17 00:00:00 2001 From: Me No Dev Date: Thu, 19 Nov 2015 22:52:52 +0200 Subject: [PATCH 1/4] Make RequestHandler handle uploads --- .../ESP8266WebServer/src/ESP8266WebServer.cpp | 18 +++---- .../ESP8266WebServer/src/ESP8266WebServer.h | 14 +++--- libraries/ESP8266WebServer/src/Parsing.cpp | 23 +++++++-- .../src/detail/RequestHandler.h | 3 ++ .../src/detail/RequestHandlersImpl.h | 47 +++++++++++++++---- 5 files changed, 77 insertions(+), 28 deletions(-) diff --git a/libraries/ESP8266WebServer/src/ESP8266WebServer.cpp b/libraries/ESP8266WebServer/src/ESP8266WebServer.cpp index 04bda3152c..de128d48eb 100644 --- a/libraries/ESP8266WebServer/src/ESP8266WebServer.cpp +++ b/libraries/ESP8266WebServer/src/ESP8266WebServer.cpp @@ -33,6 +33,7 @@ ESP8266WebServer::ESP8266WebServer(IPAddress addr, int port) : _server(addr, port) +, _currentHandler(0) , _firstHandler(0) , _lastHandler(0) , _currentArgCount(0) @@ -44,6 +45,7 @@ ESP8266WebServer::ESP8266WebServer(IPAddress addr, int port) ESP8266WebServer::ESP8266WebServer(int port) : _server(port) +, _currentHandler(0) , _firstHandler(0) , _lastHandler(0) , _currentArgCount(0) @@ -74,7 +76,11 @@ void ESP8266WebServer::on(const char* uri, ESP8266WebServer::THandlerFunction ha } void ESP8266WebServer::on(const char* uri, HTTPMethod method, ESP8266WebServer::THandlerFunction fn) { - _addRequestHandler(new FunctionRequestHandler(fn, uri, method)); + on(uri, method, fn, _fileUploadHandler); +} + +void ESP8266WebServer::on(const char* uri, HTTPMethod method, ESP8266WebServer::THandlerFunction fn, ESP8266WebServer::THandlerFunction ufn) { + _addRequestHandler(new FunctionRequestHandler(fn, ufn, uri, method)); } void ESP8266WebServer::addHandler(RequestHandler* handler) { @@ -352,13 +358,7 @@ void ESP8266WebServer::onNotFound(THandlerFunction fn) { } void ESP8266WebServer::_handleRequest() { - RequestHandler* handler; - for (handler = _firstHandler; handler; handler = handler->next()) { - if (handler->handle(*this, _currentMethod, _currentUri)) - break; - } - - if (!handler){ + if (!_currentHandler){ #ifdef DEBUG DEBUG_OUTPUT.println("request handler not found"); #endif @@ -369,6 +369,8 @@ void ESP8266WebServer::_handleRequest() { else { send(404, "text/plain", String("Not found: ") + _currentUri); } + } else { + _currentHandler->handle(*this, _currentMethod, _currentUri); } uint16_t maxWait = HTTP_MAX_CLOSE_WAIT; diff --git a/libraries/ESP8266WebServer/src/ESP8266WebServer.h b/libraries/ESP8266WebServer/src/ESP8266WebServer.h index 65e44378f6..16c9ae5a5f 100644 --- a/libraries/ESP8266WebServer/src/ESP8266WebServer.h +++ b/libraries/ESP8266WebServer/src/ESP8266WebServer.h @@ -40,12 +40,6 @@ enum HTTPUploadStatus { UPLOAD_FILE_START, UPLOAD_FILE_WRITE, UPLOAD_FILE_END, class ESP8266WebServer; -#include "detail/RequestHandler.h" - -namespace fs { -class FS; -} - typedef struct { HTTPUploadStatus status; String filename; @@ -56,6 +50,12 @@ typedef struct { uint8_t buf[HTTP_UPLOAD_BUFLEN]; } HTTPUpload; +#include "detail/RequestHandler.h" + +namespace fs { +class FS; +} + class ESP8266WebServer { public: @@ -69,6 +69,7 @@ class ESP8266WebServer typedef std::function THandlerFunction; void on(const char* uri, THandlerFunction handler); void on(const char* uri, HTTPMethod method, THandlerFunction fn); + void on(const char* uri, HTTPMethod method, THandlerFunction fn, THandlerFunction ufn); void addHandler(RequestHandler* handler); void serveStatic(const char* uri, fs::FS& fs, const char* path, const char* cache_header = NULL ); void onNotFound(THandlerFunction fn); //called when handler is not assigned @@ -155,6 +156,7 @@ template size_t streamFile(T &file, const String& contentType){ String _hostHeader; + RequestHandler* _currentHandler; RequestHandler* _firstHandler; RequestHandler* _lastHandler; THandlerFunction _notFoundHandler; diff --git a/libraries/ESP8266WebServer/src/Parsing.cpp b/libraries/ESP8266WebServer/src/Parsing.cpp index 0458a99807..318b0f547a 100644 --- a/libraries/ESP8266WebServer/src/Parsing.cpp +++ b/libraries/ESP8266WebServer/src/Parsing.cpp @@ -81,6 +81,14 @@ bool ESP8266WebServer::_parseRequest(WiFiClient& client) { DEBUG_OUTPUT.println(searchStr); #endif + //attach handler + RequestHandler* handler; + for (handler = _firstHandler; handler; handler = handler->next()) { + if (handler->canHandle(_currentMethod, _currentUri)) + break; + } + _currentHandler = handler; + String formData; // below is needed only when POST type request if (method == HTTP_POST || method == HTTP_PUT || method == HTTP_PATCH || method == HTTP_DELETE){ @@ -279,7 +287,8 @@ void ESP8266WebServer::_parseArguments(String data) { void ESP8266WebServer::_uploadWriteByte(uint8_t b){ if (_currentUpload.currentSize == HTTP_UPLOAD_BUFLEN){ - if (_fileUploadHandler) _fileUploadHandler(); + if(_currentHandler && _currentHandler->canUpload(_currentUri)) + _currentHandler->upload(*this, _currentUri, _currentUpload); _currentUpload.totalSize += _currentUpload.currentSize; _currentUpload.currentSize = 0; } @@ -397,7 +406,8 @@ bool ESP8266WebServer::_parseForm(WiFiClient& client, String boundary, uint32_t DEBUG_OUTPUT.print(" Type: "); DEBUG_OUTPUT.println(_currentUpload.type); #endif - if (_fileUploadHandler) _fileUploadHandler(); + if(_currentHandler && _currentHandler->canUpload(_currentUri)) + _currentHandler->upload(*this, _currentUri, _currentUpload); _currentUpload.status = UPLOAD_FILE_WRITE; uint8_t argByte = _uploadReadByte(client); readfile: @@ -433,10 +443,12 @@ bool ESP8266WebServer::_parseForm(WiFiClient& client, String boundary, uint32_t client.readBytes(endBuf, boundary.length()); if (strstr((const char*)endBuf, boundary.c_str()) != NULL){ - if (_fileUploadHandler) _fileUploadHandler(); + if(_currentHandler && _currentHandler->canUpload(_currentUri)) + _currentHandler->upload(*this, _currentUri, _currentUpload); _currentUpload.totalSize += _currentUpload.currentSize; _currentUpload.status = UPLOAD_FILE_END; - if (_fileUploadHandler) _fileUploadHandler(); + if(_currentHandler && _currentHandler->canUpload(_currentUri)) + _currentHandler->upload(*this, _currentUri, _currentUpload); #ifdef DEBUG DEBUG_OUTPUT.print("End File: "); DEBUG_OUTPUT.print(_currentUpload.filename); @@ -503,6 +515,7 @@ bool ESP8266WebServer::_parseForm(WiFiClient& client, String boundary, uint32_t bool ESP8266WebServer::_parseFormUploadAborted(){ _currentUpload.status = UPLOAD_FILE_ABORTED; - if (_fileUploadHandler) _fileUploadHandler(); + if(_currentHandler && _currentHandler->canUpload(_currentUri)) + _currentHandler->upload(*this, _currentUri, _currentUpload); return false; } diff --git a/libraries/ESP8266WebServer/src/detail/RequestHandler.h b/libraries/ESP8266WebServer/src/detail/RequestHandler.h index dd3d157332..5a998bfbd4 100644 --- a/libraries/ESP8266WebServer/src/detail/RequestHandler.h +++ b/libraries/ESP8266WebServer/src/detail/RequestHandler.h @@ -3,7 +3,10 @@ class RequestHandler { public: + virtual bool canHandle(HTTPMethod method, String uri) { return false; } + virtual bool canUpload(String uri) { return false; } virtual bool handle(ESP8266WebServer& server, HTTPMethod requestMethod, String requestUri) { return false; } + virtual void upload(ESP8266WebServer& server, String requestUri, HTTPUpload& upload) {} RequestHandler* next() { return _next; } void next(RequestHandler* r) { _next = r; } diff --git a/libraries/ESP8266WebServer/src/detail/RequestHandlersImpl.h b/libraries/ESP8266WebServer/src/detail/RequestHandlersImpl.h index accddee215..9ce8441e16 100644 --- a/libraries/ESP8266WebServer/src/detail/RequestHandlersImpl.h +++ b/libraries/ESP8266WebServer/src/detail/RequestHandlersImpl.h @@ -5,28 +5,49 @@ class FunctionRequestHandler : public RequestHandler { public: - FunctionRequestHandler(ESP8266WebServer::THandlerFunction fn, const char* uri, HTTPMethod method) + FunctionRequestHandler(ESP8266WebServer::THandlerFunction fn, ESP8266WebServer::THandlerFunction ufn, const char* uri, HTTPMethod method) : _fn(fn) + , _ufn(ufn) , _uri(uri) , _method(method) { } - bool handle(ESP8266WebServer& server, HTTPMethod requestMethod, String requestUri) override { + bool canHandle(HTTPMethod requestMethod, String requestUri) override { if (_method != HTTP_ANY && _method != requestMethod) return false; if (requestUri != _uri) return false; + return true; + } + + bool canUpload(String requestUri) override { + if (!_ufn || !canHandle(HTTP_POST, requestUri)) + return false; + + return true; + } + + bool handle(ESP8266WebServer& server, HTTPMethod requestMethod, String requestUri) override { + if (!canHandle(requestMethod, requestUri)) + return false; + _fn(); return true; } + void upload(ESP8266WebServer& server, String requestUri, HTTPUpload& upload) override { + if (canUpload(requestUri)) + _ufn(); + } + protected: String _uri; HTTPMethod _method; ESP8266WebServer::THandlerFunction _fn; + ESP8266WebServer::THandlerFunction _ufn; }; class StaticRequestHandler : public RequestHandler { @@ -41,13 +62,26 @@ class StaticRequestHandler : public RequestHandler { DEBUGV("StaticRequestHandler: path=%s uri=%s isFile=%d, cache_header=%s\r\n", path, uri, _isFile, cache_header); _baseUriLength = _uri.length(); } - bool handle(ESP8266WebServer& server, HTTPMethod requestMethod, String requestUri) override { + + bool canHandle(HTTPMethod requestMethod, String requestUri) override { if (requestMethod != HTTP_GET) return false; - DEBUGV("StaticRequestHandler::handle: request=%s _uri=%s\r\n", requestUri.c_str(), _uri.c_str()); + if (!requestUri.startsWith(_uri)) return false; + if (requestUri != _uri) + return false; + + return true; + } + + bool handle(ESP8266WebServer& server, HTTPMethod requestMethod, String requestUri) override { + if (!canHandle(requestMethod, requestUri)) + return false; + + DEBUGV("StaticRequestHandler::handle: request=%s _uri=%s\r\n", requestUri.c_str(), _uri.c_str()); + String path(_path); if(path.endsWith("/")) path += "index.htm"; @@ -57,11 +91,6 @@ class StaticRequestHandler : public RequestHandler { // URI in request to get the file path. path += requestUri.substring(_baseUriLength); } - - else if (requestUri != _uri) { - // Base URI points to a file but request doesn't match this URI exactly - return false; - } DEBUGV("StaticRequestHandler::handle: path=%s, isFile=%d\r\n", path.c_str(), _isFile); String contentType = getContentType(path); From 0063d80c740c3a605cb298169452104c34e0d892 Mon Sep 17 00:00:00 2001 From: Me No Dev Date: Thu, 19 Nov 2015 23:20:03 +0200 Subject: [PATCH 2/4] "Fix" sketches and libs to use the new upload api --- .../src/ESP8266HTTPUpdateServer.cpp | 11 ++++------- .../examples/FSBrowser/FSBrowser.ino | 7 +++---- .../examples/SDWebServer/SDWebServer.ino | 3 +-- .../examples/WebUpdate/WebUpdate.ino | 14 ++++++-------- 4 files changed, 14 insertions(+), 21 deletions(-) diff --git a/libraries/ESP8266HTTPUpdateServer/src/ESP8266HTTPUpdateServer.cpp b/libraries/ESP8266HTTPUpdateServer/src/ESP8266HTTPUpdateServer.cpp index 2ed37c5022..fa7b7ac35a 100644 --- a/libraries/ESP8266HTTPUpdateServer/src/ESP8266HTTPUpdateServer.cpp +++ b/libraries/ESP8266HTTPUpdateServer/src/ESP8266HTTPUpdateServer.cpp @@ -36,12 +36,9 @@ void ESP8266HTTPUpdateServer::setup(ESP8266WebServer *server) _server->sendHeader("Access-Control-Allow-Origin", "*"); _server->send(200, "text/plain", (Update.hasError())?"FAIL":"OK"); ESP.restart(); - }); - - // handler for the file upload, get's the sketch bytes, and writes - // them through the Update object. - _server->onFileUpload([&](){ - if(_server->uri() != "/update") return; + },[&](){ + // handler for the file upload, get's the sketch bytes, and writes + // them through the Update object HTTPUpload& upload = _server->upload(); if(upload.status == UPLOAD_FILE_START){ if (_serial_output) @@ -70,6 +67,6 @@ void ESP8266HTTPUpdateServer::setup(ESP8266WebServer *server) Update.end(); if (_serial_output) Serial.println("Update was aborted"); } - yield(); + delay(0); }); } diff --git a/libraries/ESP8266WebServer/examples/FSBrowser/FSBrowser.ino b/libraries/ESP8266WebServer/examples/FSBrowser/FSBrowser.ino index f8b43e34d5..4df717d701 100644 --- a/libraries/ESP8266WebServer/examples/FSBrowser/FSBrowser.ino +++ b/libraries/ESP8266WebServer/examples/FSBrowser/FSBrowser.ino @@ -207,10 +207,9 @@ void setup(void){ server.on("/edit", HTTP_PUT, handleFileCreate); //delete file server.on("/edit", HTTP_DELETE, handleFileDelete); - //called after file upload - server.on("/edit", HTTP_POST, [](){ server.send(200, "text/plain", ""); }); - //called when a file is received inside POST data - server.onFileUpload(handleFileUpload); + //first callback is called after the request has ended with all parsed arguments + //second callback handles file uploads at that location + server.on("/edit", HTTP_POST, [](){ server.send(200, "text/plain", ""); }, handleFileUpload); //called when the url is not defined here //use it to load content from SPIFFS diff --git a/libraries/ESP8266WebServer/examples/SDWebServer/SDWebServer.ino b/libraries/ESP8266WebServer/examples/SDWebServer/SDWebServer.ino index c62cadfd60..b42b1d097f 100644 --- a/libraries/ESP8266WebServer/examples/SDWebServer/SDWebServer.ino +++ b/libraries/ESP8266WebServer/examples/SDWebServer/SDWebServer.ino @@ -256,9 +256,8 @@ void setup(void){ server.on("/list", HTTP_GET, printDirectory); server.on("/edit", HTTP_DELETE, handleDelete); server.on("/edit", HTTP_PUT, handleCreate); - server.on("/edit", HTTP_POST, [](){ returnOK(); }); + server.on("/edit", HTTP_POST, [](){ returnOK(); }, handleFileUpload); server.onNotFound(handleNotFound); - server.onFileUpload(handleFileUpload); server.begin(); DBG_OUTPUT_PORT.println("HTTP server started"); diff --git a/libraries/ESP8266WebServer/examples/WebUpdate/WebUpdate.ino b/libraries/ESP8266WebServer/examples/WebUpdate/WebUpdate.ino index 665dd61996..c5e67ef33a 100644 --- a/libraries/ESP8266WebServer/examples/WebUpdate/WebUpdate.ino +++ b/libraries/ESP8266WebServer/examples/WebUpdate/WebUpdate.ino @@ -27,8 +27,12 @@ void setup(void){ server.sendHeader("Access-Control-Allow-Origin", "*"); server.send(200, "text/html", serverIndex); }); - server.onFileUpload([](){ - if(server.uri() != "/update") return; + server.on("/update", HTTP_POST, [](){ + server.sendHeader("Connection", "close"); + server.sendHeader("Access-Control-Allow-Origin", "*"); + server.send(200, "text/plain", (Update.hasError())?"FAIL":"OK"); + ESP.restart(); + },[](){ HTTPUpload& upload = server.upload(); if(upload.status == UPLOAD_FILE_START){ Serial.setDebugOutput(true); @@ -52,12 +56,6 @@ void setup(void){ } yield(); }); - server.on("/update", HTTP_POST, [](){ - server.sendHeader("Connection", "close"); - server.sendHeader("Access-Control-Allow-Origin", "*"); - server.send(200, "text/plain", (Update.hasError())?"FAIL":"OK"); - ESP.restart(); - }); server.begin(); MDNS.addService("http", "tcp", 80); From 94a7f63cda2516a3ec35be7a11faf098dda31014 Mon Sep 17 00:00:00 2001 From: Me No Dev Date: Sat, 21 Nov 2015 21:04:07 +0200 Subject: [PATCH 3/4] fix static handler --- .../ESP8266WebServer/src/detail/RequestHandlersImpl.h | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/libraries/ESP8266WebServer/src/detail/RequestHandlersImpl.h b/libraries/ESP8266WebServer/src/detail/RequestHandlersImpl.h index 9ce8441e16..54522b1d96 100644 --- a/libraries/ESP8266WebServer/src/detail/RequestHandlersImpl.h +++ b/libraries/ESP8266WebServer/src/detail/RequestHandlersImpl.h @@ -70,9 +70,6 @@ class StaticRequestHandler : public RequestHandler { if (!requestUri.startsWith(_uri)) return false; - if (requestUri != _uri) - return false; - return true; } @@ -91,6 +88,11 @@ class StaticRequestHandler : public RequestHandler { // URI in request to get the file path. path += requestUri.substring(_baseUriLength); } + + else if (requestUri != _uri) { + // Base URI points to a file but request doesn't match this URI exactly + return false; + } DEBUGV("StaticRequestHandler::handle: path=%s, isFile=%d\r\n", path.c_str(), _isFile); String contentType = getContentType(path); From bc48022118f3c18cce659795d73628df7e47dc86 Mon Sep 17 00:00:00 2001 From: Me No Dev Date: Sat, 21 Nov 2015 21:29:54 +0200 Subject: [PATCH 4/4] spend more time understanding the logic --- .../ESP8266WebServer/src/detail/RequestHandlersImpl.h | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/libraries/ESP8266WebServer/src/detail/RequestHandlersImpl.h b/libraries/ESP8266WebServer/src/detail/RequestHandlersImpl.h index 54522b1d96..4ff6a3a42e 100644 --- a/libraries/ESP8266WebServer/src/detail/RequestHandlersImpl.h +++ b/libraries/ESP8266WebServer/src/detail/RequestHandlersImpl.h @@ -67,8 +67,8 @@ class StaticRequestHandler : public RequestHandler { if (requestMethod != HTTP_GET) return false; - if (!requestUri.startsWith(_uri)) - return false; + if (_isFile && requestUri != _uri || !requestUri.startsWith(_uri)) + return false; return true; } @@ -88,11 +88,6 @@ class StaticRequestHandler : public RequestHandler { // URI in request to get the file path. path += requestUri.substring(_baseUriLength); } - - else if (requestUri != _uri) { - // Base URI points to a file but request doesn't match this URI exactly - return false; - } DEBUGV("StaticRequestHandler::handle: path=%s, isFile=%d\r\n", path.c_str(), _isFile); String contentType = getContentType(path);