diff --git a/libraries/ArduinoOTA/ArduinoOTA.cpp b/libraries/ArduinoOTA/ArduinoOTA.cpp index 744c208cc..9b55733bb 100644 --- a/libraries/ArduinoOTA/ArduinoOTA.cpp +++ b/libraries/ArduinoOTA/ArduinoOTA.cpp @@ -1,9 +1,23 @@ -#include -#include +#define LWIP_OPEN_SRC +#include #include #include "ArduinoOTA.h" #include "MD5Builder.h" +extern "C" { + #include "osapi.h" + #include "ets_sys.h" + #include "user_interface.h" +} + +#include "lwip/opt.h" +#include "lwip/udp.h" +#include "lwip/inet.h" +#include "lwip/igmp.h" +#include "lwip/mem.h" +#include "include/UdpContext.h" +#include + //#define OTA_DEBUG 1 ArduinoOTAClass::ArduinoOTAClass() @@ -16,9 +30,17 @@ ArduinoOTAClass::ArduinoOTAClass() , _end_callback(NULL) , _progress_callback(NULL) , _error_callback(NULL) +, _udp_ota(0) { } +ArduinoOTAClass::~ArduinoOTAClass(){ + if(_udp_ota){ + _udp_ota->unref(); + _udp_ota = 0; + } +} + void ArduinoOTAClass::onStart(OTA_CALLBACK(fn)) { _start_callback = fn; } @@ -35,9 +57,6 @@ void ArduinoOTAClass::onError(OTA_CALLBACK_ERROR(fn)) { _error_callback = fn; } -ArduinoOTAClass::~ArduinoOTAClass() { -} - void ArduinoOTAClass::setPort(uint16_t port) { if (!_initialized && !_port && port) { _port = port; @@ -59,7 +78,6 @@ void ArduinoOTAClass::setPassword(const char * password) { void ArduinoOTAClass::begin() { if (_initialized) return; - _initialized = true; if (!_hostname.length()) { char tmp[15]; @@ -70,7 +88,17 @@ void ArduinoOTAClass::begin() { _port = 8266; } - _udp_ota.begin(_port); + if(_udp_ota){ + _udp_ota->unref(); + _udp_ota = 0; + } + + _udp_ota = new UdpContext; + _udp_ota->ref(); + + if(!_udp_ota->listen(*IP_ADDR_ANY, _port)) + return; + _udp_ota->onRx(std::bind(&ArduinoOTAClass::_onRx, this)); MDNS.begin(_hostname.c_str()); if (_password.length()) { @@ -78,12 +106,123 @@ void ArduinoOTAClass::begin() { } else { MDNS.enableArduino(_port); } + _initialized = true; _state = OTA_IDLE; #if OTA_DEBUG Serial.printf("OTA server at: %s.local:%u\n", _hostname.c_str(), _port); #endif } +int ArduinoOTAClass::parseInt(){ + char data[16]; + uint8_t index = 0; + char value; + while(_udp_ota->peek() == ' ') _udp_ota->read(); + while(true){ + value = _udp_ota->peek(); + if(value < '0' || value > '9'){ + data[index++] = '\0'; + return atoi(data); + } + data[index++] = _udp_ota->read(); + } + return 0; +} + +String ArduinoOTAClass::readStringUntil(char end){ + String res = ""; + char value; + while(true){ + value = _udp_ota->read(); + if(value == '\0' || value == end){ + return res; + } + res += value; + } + return res; +} + +void ArduinoOTAClass::_onRx(){ + if(!_udp_ota->next()) return; + ip_addr_t ota_ip; + + if (_state == OTA_IDLE) { + int cmd = parseInt(); + if (cmd != U_FLASH && cmd != U_SPIFFS) + return; + _ota_ip = _udp_ota->getRemoteAddress(); + _cmd = cmd; + _ota_port = parseInt(); + _size = parseInt(); + _udp_ota->read(); + _md5 = readStringUntil('\n'); + _md5.trim(); + if(_md5.length() != 32) + return; + + ota_ip.addr = (uint32_t)_ota_ip; + + if (_password.length()){ + MD5Builder nonce_md5; + nonce_md5.begin(); + nonce_md5.add(String(micros())); + nonce_md5.calculate(); + _nonce = nonce_md5.toString(); + + char auth_req[38]; + sprintf(auth_req, "AUTH %s", _nonce.c_str()); + _udp_ota->append((const char *)auth_req, strlen(auth_req)); + _udp_ota->send(&ota_ip, _udp_ota->getRemotePort()); + _state = OTA_WAITAUTH; + return; + } else { + _udp_ota->append("OK", 2); + _udp_ota->send(&ota_ip, _udp_ota->getRemotePort()); + _state = OTA_RUNUPDATE; + } + } else if (_state == OTA_WAITAUTH) { + int cmd = parseInt(); + if (cmd != U_AUTH) { + _state = OTA_IDLE; + return; + } + _udp_ota->read(); + String cnonce = readStringUntil(' '); + String response = readStringUntil('\n'); + if (cnonce.length() != 32 || response.length() != 32) { + _state = OTA_IDLE; + return; + } + + MD5Builder _passmd5; + _passmd5.begin(); + _passmd5.add(_password); + _passmd5.calculate(); + String passmd5 = _passmd5.toString(); + + String challenge = passmd5 + ":" + String(_nonce) + ":" + cnonce; + MD5Builder _challengemd5; + _challengemd5.begin(); + _challengemd5.add(challenge); + _challengemd5.calculate(); + String result = _challengemd5.toString(); + + ota_ip.addr = (uint32_t)_ota_ip; + if(result.equals(response)){ + _udp_ota->append("OK", 2); + _udp_ota->send(&ota_ip, _udp_ota->getRemotePort()); + _state = OTA_RUNUPDATE; + } else { + _udp_ota->append("Authentication Failed", 21); + _udp_ota->send(&ota_ip, _udp_ota->getRemotePort()); + if (_error_callback) _error_callback(OTA_AUTH_ERROR); + _state = OTA_IDLE; + } + } + + while(_udp_ota->next()) _udp_ota->flush(); +} + void ArduinoOTAClass::_runUpdate() { if (!Update.begin(_size, _cmd)) { #if OTA_DEBUG @@ -92,7 +231,7 @@ void ArduinoOTAClass::_runUpdate() { if (_error_callback) { _error_callback(OTA_BEGIN_ERROR); } - _udp_ota.begin(_port); + _udp_ota->listen(*IP_ADDR_ANY, _port); _state = OTA_IDLE; return; } @@ -112,7 +251,7 @@ void ArduinoOTAClass::_runUpdate() { #if OTA_DEBUG Serial.printf("Connect Failed\n"); #endif - _udp_ota.begin(_port); + _udp_ota->listen(*IP_ADDR_ANY, _port); if (_error_callback) { _error_callback(OTA_CONNECT_ERROR); } @@ -128,7 +267,7 @@ void ArduinoOTAClass::_runUpdate() { #if OTA_DEBUG Serial.printf("Recieve Failed\n"); #endif - _udp_ota.begin(_port); + _udp_ota->listen(*IP_ADDR_ANY, _port); if (_error_callback) { _error_callback(OTA_RECIEVE_ERROR); } @@ -156,7 +295,7 @@ void ArduinoOTAClass::_runUpdate() { } ESP.restart(); } else { - _udp_ota.begin(_port); + _udp_ota->listen(*IP_ADDR_ANY, _port); if (_error_callback) { _error_callback(OTA_END_ERROR); } @@ -169,94 +308,9 @@ void ArduinoOTAClass::_runUpdate() { } void ArduinoOTAClass::handle() { - if (!_udp_ota) { - _udp_ota.begin(_port); -#if OTA_DEBUG - Serial.println("OTA restarted"); -#endif - } - - if (!_udp_ota.parsePacket()) return; - - if (_state == OTA_IDLE) { - int cmd = _udp_ota.parseInt(); - if (cmd != U_FLASH && cmd != U_SPIFFS) - return; - _ota_ip = _udp_ota.remoteIP(); - _cmd = cmd; - _ota_port = _udp_ota.parseInt(); - _size = _udp_ota.parseInt(); - _udp_ota.read(); - _md5 = _udp_ota.readStringUntil('\n'); - _md5.trim(); - if(_md5.length() != 32) - return; - -#if OTA_DEBUG - Serial.print("Update Start: ip:"); - Serial.print(_ota_ip); - Serial.printf(", port:%d, size:%d, md5:%s\n", _ota_port, _size, _md5.c_str()); -#endif - - _udp_ota.beginPacket(_ota_ip, _udp_ota.remotePort()); - if (_password.length()){ - MD5Builder nonce_md5; - nonce_md5.begin(); - nonce_md5.add(String(micros())); - nonce_md5.calculate(); - _nonce = nonce_md5.toString(); - _udp_ota.printf("AUTH %s", _nonce.c_str()); - _udp_ota.endPacket(); - _state = OTA_WAITAUTH; - return; - } else { - _udp_ota.print("OK"); - _udp_ota.endPacket(); - _state = OTA_RUNUPDATE; - } - } else if (_state == OTA_WAITAUTH) { - int cmd = _udp_ota.parseInt(); - if (cmd != U_AUTH) { - _state = OTA_IDLE; - return; - } - _udp_ota.read(); - String cnonce = _udp_ota.readStringUntil(' '); - String response = _udp_ota.readStringUntil('\n'); - if (cnonce.length() != 32 || response.length() != 32) { - _state = OTA_IDLE; - return; - } - - MD5Builder _passmd5; - _passmd5.begin(); - _passmd5.add(_password); - _passmd5.calculate(); - String passmd5 = _passmd5.toString(); - - String challenge = passmd5 + ":" + String(_nonce) + ":" + cnonce; - MD5Builder _challengemd5; - _challengemd5.begin(); - _challengemd5.add(challenge); - _challengemd5.calculate(); - String result = _challengemd5.toString(); - - if(result.equals(response)){ - _udp_ota.beginPacket(_ota_ip, _udp_ota.remotePort()); - _udp_ota.print("OK"); - _udp_ota.endPacket(); - _state = OTA_RUNUPDATE; - } else { - _udp_ota.beginPacket(_ota_ip, _udp_ota.remotePort()); - _udp_ota.print("Authentication Failed"); - _udp_ota.endPacket(); - if (_error_callback) _error_callback(OTA_AUTH_ERROR); - _state = OTA_IDLE; - } - } - if (_state == OTA_RUNUPDATE) { _runUpdate(); + _state = OTA_IDLE; } } diff --git a/libraries/ArduinoOTA/ArduinoOTA.h b/libraries/ArduinoOTA/ArduinoOTA.h index 5d5161e5e..bdb839397 100644 --- a/libraries/ArduinoOTA/ArduinoOTA.h +++ b/libraries/ArduinoOTA/ArduinoOTA.h @@ -1,7 +1,10 @@ #ifndef __ARDUINO_OTA_H #define __ARDUINO_OTA_H -class WiFiUDP; +#include +#include + +class UdpContext; #define OTA_CALLBACK(callback) void (*callback)() #define OTA_CALLBACK_PROGRESS(callback) void (*callback)(unsigned int, unsigned int) @@ -41,7 +44,7 @@ class ArduinoOTAClass String _password; String _hostname; String _nonce; - WiFiUDP _udp_ota; + UdpContext *_udp_ota; bool _initialized; ota_state_t _state; int _size; @@ -56,6 +59,9 @@ class ArduinoOTAClass OTA_CALLBACK_PROGRESS(_progress_callback); void _runUpdate(void); + void _onRx(void); + int parseInt(void); + String readStringUntil(char end); }; extern ArduinoOTAClass ArduinoOTA; diff --git a/libraries/ESP8266HTTPUpdateServer/src/ESP8266HTTPUpdateServer.cpp b/libraries/ESP8266HTTPUpdateServer/src/ESP8266HTTPUpdateServer.cpp index 2ed37c502..fa7b7ac35 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 f8b43e34d..4df717d70 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 c62cadfd6..b42b1d097 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 665dd6199..c5e67ef33 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); diff --git a/libraries/ESP8266WebServer/src/ESP8266WebServer.cpp b/libraries/ESP8266WebServer/src/ESP8266WebServer.cpp index 04bda3152..de128d48e 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 65e44378f..16c9ae5a5 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 @@ public: 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 @@ protected: 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 0458a9980..318b0f547 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 @@ readfile: 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 @@ readfile: 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 dd3d15733..5a998bfbd 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 accddee21..4ff6a3a42 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,12 +62,22 @@ public: 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)) + + if (_isFile && requestUri != _uri || !requestUri.startsWith(_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); @@ -57,11 +88,6 @@ public: // 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);