1
0
mirror of https://github.com/esp8266/Arduino.git synced 2025-04-19 23:22:16 +03:00

webserver hook: allow to handle external http protocol (#7459)

* webhook api
* simplify webserver debug printouts, move text to flash
* Hook examples in HelloServer example
* print executable code address in example
* simplify example per @mcspr suggestion
This commit is contained in:
david gauchard 2020-07-28 23:34:26 +02:00 committed by GitHub
parent 63b41bcfab
commit 33083861c8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 187 additions and 144 deletions

View File

@ -92,7 +92,19 @@ inline uint32_t esp_get_cycle_count() {
__asm__ __volatile__("rsr %0,ccount":"=a"(ccount)); __asm__ __volatile__("rsr %0,ccount":"=a"(ccount));
return ccount; return ccount;
} }
#endif // not CORE_MOCK
inline uint32_t esp_get_program_counter() __attribute__((always_inline));
inline uint32_t esp_get_program_counter() {
uint32_t pc;
__asm__ __volatile__("movi %0, ." : "=r" (pc) : : ); // ©earlephilhower
return pc;
}
#else // CORE_MOCK
inline uint32_t esp_get_program_counter() { return 0; }
#endif // CORE_MOCK
// Tools for preloading code into the flash cache // Tools for preloading code into the flash cache

View File

@ -17,7 +17,7 @@ const int led = 13;
void handleRoot() { void handleRoot() {
digitalWrite(led, 1); digitalWrite(led, 1);
server.send(200, "text/plain", "hello from esp8266!"); server.send(200, "text/plain", "hello from esp8266!\r\n");
digitalWrite(led, 0); digitalWrite(led, 0);
} }
@ -86,6 +86,66 @@ void setup(void) {
server.onNotFound(handleNotFound); server.onNotFound(handleNotFound);
/////////////////////////////////////////////////////////
// Hook examples
server.addHook([](const String & method, const String & url, WiFiClient * client, ESP8266WebServer::ContentTypeFunction contentType) {
(void)method; // GET, PUT, ...
(void)url; // example: /root/myfile.html
(void)client; // the webserver tcp client connection
(void)contentType; // contentType(".html") => "text/html"
Serial.printf("A useless web hook has passed\n");
Serial.printf("(this hook is in 0x%08x area (401x=IRAM 402x=FLASH))\n", esp_get_program_counter());
return ESP8266WebServer::CLIENT_REQUEST_CAN_CONTINUE;
});
server.addHook([](const String&, const String & url, WiFiClient*, ESP8266WebServer::ContentTypeFunction) {
if (url.startsWith("/fail")) {
Serial.printf("An always failing web hook has been triggered\n");
return ESP8266WebServer::CLIENT_MUST_STOP;
}
return ESP8266WebServer::CLIENT_REQUEST_CAN_CONTINUE;
});
server.addHook([](const String&, const String & url, WiFiClient * client, ESP8266WebServer::ContentTypeFunction) {
if (url.startsWith("/dump")) {
Serial.printf("The dumper web hook is on the run\n");
// Here the request is not interpreted, so we cannot for sure
// swallow the exact amount matching the full request+content,
// hence the tcp connection cannot be handled anymore by the
// webserver.
#ifdef STREAMTO_API
// we are lucky
client->toWithTimeout(Serial, 500);
#else
auto last = millis();
while ((millis() - last) < 500) {
char buf[32];
size_t len = client->read((uint8_t*)buf, sizeof(buf));
if (len > 0) {
Serial.printf("(<%d> chars)", (int)len);
Serial.write(buf, len);
last = millis();
}
}
#endif
// Two choices: return MUST STOP and webserver will close it
// (we already have the example with '/fail' hook)
// or IS GIVEN and webserver will forget it
// trying with IS GIVEN and storing it on a dumb WiFiClient.
// check the client connection: it should not immediately be closed
// (make another '/dump' one to close the first)
Serial.printf("\nTelling server to forget this connection\n");
static WiFiClient forgetme = *client; // stop previous one if present and transfer client refcounter
return ESP8266WebServer::CLIENT_IS_GIVEN;
}
return ESP8266WebServer::CLIENT_REQUEST_CAN_CONTINUE;
});
// Hook examples
/////////////////////////////////////////////////////////
server.begin(); server.begin();
Serial.println("HTTP server started"); Serial.println("HTTP server started");
} }

View File

@ -28,20 +28,12 @@
#include "FS.h" #include "FS.h"
#include "detail/RequestHandlersImpl.h" #include "detail/RequestHandlersImpl.h"
//#define DEBUG_ESP_HTTP_SERVER
#ifdef DEBUG_ESP_PORT
#define DEBUG_OUTPUT DEBUG_ESP_PORT
#else
#define DEBUG_OUTPUT Serial
#endif
static const char AUTHORIZATION_HEADER[] PROGMEM = "Authorization"; static const char AUTHORIZATION_HEADER[] PROGMEM = "Authorization";
static const char qop_auth[] PROGMEM = "qop=auth"; static const char qop_auth[] PROGMEM = "qop=auth";
static const char qop_auth_quoted[] PROGMEM = "qop=\"auth\""; static const char qop_auth_quoted[] PROGMEM = "qop=\"auth\"";
static const char WWW_Authenticate[] PROGMEM = "WWW-Authenticate"; static const char WWW_Authenticate[] PROGMEM = "WWW-Authenticate";
static const char Content_Length[] PROGMEM = "Content-Length"; static const char Content_Length[] PROGMEM = "Content-Length";
template <typename ServerType> template <typename ServerType>
ESP8266WebServerTemplate<ServerType>::ESP8266WebServerTemplate(IPAddress addr, int port) ESP8266WebServerTemplate<ServerType>::ESP8266WebServerTemplate(IPAddress addr, int port)
: _server(addr, port) : _server(addr, port)
@ -171,9 +163,7 @@ bool ESP8266WebServerTemplate<ServerType>::authenticateDigest(const String& user
String authReq = header(FPSTR(AUTHORIZATION_HEADER)); String authReq = header(FPSTR(AUTHORIZATION_HEADER));
if(authReq.startsWith(F("Digest"))) { if(authReq.startsWith(F("Digest"))) {
authReq = authReq.substring(7); authReq = authReq.substring(7);
#ifdef DEBUG_ESP_HTTP_SERVER DBGWS("%s\n", authReq.c_str());
DEBUG_OUTPUT.println(authReq);
#endif
String _username = _extractParam(authReq,F("username=\"")); String _username = _extractParam(authReq,F("username=\""));
if(!_username.length() || _username != String(username)) { if(!_username.length() || _username != String(username)) {
authReq = ""; authReq = "";
@ -200,9 +190,7 @@ bool ESP8266WebServerTemplate<ServerType>::authenticateDigest(const String& user
_nc = _extractParam(authReq, F("nc="), ','); _nc = _extractParam(authReq, F("nc="), ',');
_cnonce = _extractParam(authReq, F("cnonce=\"")); _cnonce = _extractParam(authReq, F("cnonce=\""));
} }
#ifdef DEBUG_ESP_HTTP_SERVER DBGWS("Hash of user:realm:pass=%s\n", H1.c_str());
DEBUG_OUTPUT.println("Hash of user:realm:pass=" + H1);
#endif
MD5Builder md5; MD5Builder md5;
md5.begin(); md5.begin();
if(_currentMethod == HTTP_GET){ if(_currentMethod == HTTP_GET){
@ -218,9 +206,7 @@ bool ESP8266WebServerTemplate<ServerType>::authenticateDigest(const String& user
} }
md5.calculate(); md5.calculate();
String _H2 = md5.toString(); String _H2 = md5.toString();
#ifdef DEBUG_ESP_HTTP_SERVER DBGWS("Hash of GET:uri=%s\n", _H2.c_str());
DEBUG_OUTPUT.println("Hash of GET:uri=" + _H2);
#endif
md5.begin(); md5.begin();
if(authReq.indexOf(FPSTR(qop_auth)) != -1 || authReq.indexOf(FPSTR(qop_auth_quoted)) != -1) { if(authReq.indexOf(FPSTR(qop_auth)) != -1 || authReq.indexOf(FPSTR(qop_auth_quoted)) != -1) {
md5.add(H1 + ':' + _nonce + ':' + _nc + ':' + _cnonce + F(":auth:") + _H2); md5.add(H1 + ':' + _nonce + ':' + _nc + ':' + _cnonce + F(":auth:") + _H2);
@ -229,9 +215,7 @@ bool ESP8266WebServerTemplate<ServerType>::authenticateDigest(const String& user
} }
md5.calculate(); md5.calculate();
String _responsecheck = md5.toString(); String _responsecheck = md5.toString();
#ifdef DEBUG_ESP_HTTP_SERVER DBGWS("The Proper response=%s\n", _responsecheck.c_str());
DEBUG_OUTPUT.println("The Proper response=" +_responsecheck);
#endif
if(_response == _responsecheck){ if(_response == _responsecheck){
authReq = ""; authReq = "";
return true; return true;
@ -315,9 +299,7 @@ void ESP8266WebServerTemplate<ServerType>::handleClient() {
return; return;
} }
#ifdef DEBUG_ESP_HTTP_SERVER DBGWS("New client\n");
DEBUG_OUTPUT.println("New client");
#endif
_currentClient = client; _currentClient = client;
_currentStatus = HC_WAIT_READ; _currentStatus = HC_WAIT_READ;
@ -327,6 +309,13 @@ void ESP8266WebServerTemplate<ServerType>::handleClient() {
bool keepCurrentClient = false; bool keepCurrentClient = false;
bool callYield = false; bool callYield = false;
DBGWS("http-server loop: conn=%d avail=%d status=%s\n",
_currentClient.connected(), _currentClient.available(),
_currentStatus==HC_NONE?"none":
_currentStatus==HC_WAIT_READ?"wait-read":
_currentStatus==HC_WAIT_CLOSE?"wait-close":
"??");
if (_currentClient.connected() || _currentClient.available()) { if (_currentClient.connected() || _currentClient.available()) {
if (_currentClient.available() && _keepAlive) { if (_currentClient.available() && _keepAlive) {
_currentStatus = HC_WAIT_READ; _currentStatus = HC_WAIT_READ;
@ -339,34 +328,57 @@ void ESP8266WebServerTemplate<ServerType>::handleClient() {
case HC_WAIT_READ: case HC_WAIT_READ:
// Wait for data from client to become available // Wait for data from client to become available
if (_currentClient.available()) { if (_currentClient.available()) {
if (_parseRequest(_currentClient)) { switch (_parseRequest(_currentClient))
{
case CLIENT_REQUEST_CAN_CONTINUE:
_currentClient.setTimeout(HTTP_MAX_SEND_WAIT); _currentClient.setTimeout(HTTP_MAX_SEND_WAIT);
_contentLength = CONTENT_LENGTH_NOT_SET; _contentLength = CONTENT_LENGTH_NOT_SET;
_handleRequest(); _handleRequest();
/* fallthrough */
if (_currentClient.connected()) { case CLIENT_REQUEST_IS_HANDLED:
if (_currentClient.connected() || _currentClient.available()) {
_currentStatus = HC_WAIT_CLOSE; _currentStatus = HC_WAIT_CLOSE;
_statusChange = millis(); _statusChange = millis();
keepCurrentClient = true; keepCurrentClient = true;
} }
} else
} else { // !_currentClient.available() DBGWS("webserver: peer has closed after served\n");
break;
case CLIENT_MUST_STOP:
DBGWS("Close client\n");
_currentClient.stop();
break;
case CLIENT_IS_GIVEN:
// client must not be stopped but must not be handled here anymore
// (example: tcp connection given to websocket)
DBGWS("Give client\n");
break;
} // switch _parseRequest()
} else {
// !_currentClient.available(): waiting for more data
if (millis() - _statusChange <= HTTP_MAX_DATA_WAIT) { if (millis() - _statusChange <= HTTP_MAX_DATA_WAIT) {
keepCurrentClient = true; keepCurrentClient = true;
} }
else
DBGWS("webserver: closing after read timeout\n");
callYield = true; callYield = true;
} }
break; break;
case HC_WAIT_CLOSE: case HC_WAIT_CLOSE:
// Wait for client to close the connection // Wait for client to close the connection
if (millis() - _statusChange <= HTTP_MAX_CLOSE_WAIT) { if (!_server.available() && (millis() - _statusChange <= HTTP_MAX_CLOSE_WAIT)) {
keepCurrentClient = true; keepCurrentClient = true;
callYield = true; callYield = true;
if (_currentClient.available())
// continue serving current client
_currentStatus = HC_WAIT_READ;
} }
} break;
} // switch _currentStatus
} }
if (!keepCurrentClient) { if (!keepCurrentClient) {
DBGWS("Drop client\n");
_currentClient = ClientType(); _currentClient = ClientType();
_currentStatus = HC_NONE; _currentStatus = HC_NONE;
_currentUpload.reset(); _currentUpload.reset();
@ -687,17 +699,13 @@ template <typename ServerType>
void ESP8266WebServerTemplate<ServerType>::_handleRequest() { void ESP8266WebServerTemplate<ServerType>::_handleRequest() {
bool handled = false; bool handled = false;
if (!_currentHandler){ if (!_currentHandler){
#ifdef DEBUG_ESP_HTTP_SERVER DBGWS("request handler not found\n");
DEBUG_OUTPUT.println("request handler not found");
#endif
} }
else { else {
handled = _currentHandler->handle(*this, _currentMethod, _currentUri); handled = _currentHandler->handle(*this, _currentMethod, _currentUri);
#ifdef DEBUG_ESP_HTTP_SERVER
if (!handled) { if (!handled) {
DEBUG_OUTPUT.println("request handler failed to handle request"); DBGWS("request handler failed to handle request\n");
} }
#endif
} }
if (!handled && _notFoundHandler) { if (!handled && _notFoundHandler) {
_notFoundHandler(); _notFoundHandler();

View File

@ -26,11 +26,24 @@
#include <functional> #include <functional>
#include <memory> #include <memory>
#include <functional>
#include <ESP8266WiFi.h> #include <ESP8266WiFi.h>
#include <FS.h> #include <FS.h>
#include "detail/mimetable.h" #include "detail/mimetable.h"
#include "Uri.h" #include "Uri.h"
//#define DEBUG_ESP_HTTP_SERVER
#ifdef DEBUG_ESP_HTTP_SERVER
#ifdef DEBUG_ESP_PORT
#define DBGWS(f,...) do { DEBUG_ESP_PORT.printf(PSTR(f), ##__VA_ARGS__); } while (0)
#else
#define DBGWS(f,...) do { Serial.printf(PSTR(f), ##__VA_ARGS__); } while (0)
#endif
#else
#define DBGWS(x...) do { (void)0; } while (0)
#endif
enum HTTPMethod { HTTP_ANY, HTTP_GET, HTTP_HEAD, HTTP_POST, HTTP_PUT, HTTP_PATCH, HTTP_DELETE, HTTP_OPTIONS }; enum HTTPMethod { HTTP_ANY, HTTP_GET, HTTP_HEAD, HTTP_POST, HTTP_PUT, HTTP_PATCH, HTTP_DELETE, HTTP_OPTIONS };
enum HTTPUploadStatus { UPLOAD_FILE_START, UPLOAD_FILE_WRITE, UPLOAD_FILE_END, enum HTTPUploadStatus { UPLOAD_FILE_START, UPLOAD_FILE_WRITE, UPLOAD_FILE_END,
UPLOAD_FILE_ABORTED }; UPLOAD_FILE_ABORTED };
@ -80,6 +93,9 @@ public:
using ClientType = typename ServerType::ClientType; using ClientType = typename ServerType::ClientType;
using RequestHandlerType = RequestHandler<ServerType>; using RequestHandlerType = RequestHandler<ServerType>;
using WebServerType = ESP8266WebServerTemplate<ServerType>; using WebServerType = ESP8266WebServerTemplate<ServerType>;
enum ClientFuture { CLIENT_REQUEST_CAN_CONTINUE, CLIENT_REQUEST_IS_HANDLED, CLIENT_MUST_STOP, CLIENT_IS_GIVEN };
typedef String (*ContentTypeFunction) (const String&);
using HookFunction = std::function<ClientFuture(const String& method, const String& url, WiFiClient* client, ContentTypeFunction contentType)>;
void begin(); void begin();
void begin(uint16_t port); void begin(uint16_t port);
@ -200,11 +216,25 @@ public:
static String responseCodeToString(const int code); static String responseCodeToString(const int code);
void addHook (HookFunction hook) {
if (_hook) {
auto previousHook = _hook;
_hook = [previousHook, hook](const String& method, const String& url, WiFiClient* client, ContentTypeFunction contentType) {
auto whatNow = previousHook(method, url, client, contentType);
if (whatNow == CLIENT_REQUEST_CAN_CONTINUE)
return hook(method, url, client, contentType);
return whatNow;
};
} else {
_hook = hook;
}
}
protected: protected:
void _addRequestHandler(RequestHandlerType* handler); void _addRequestHandler(RequestHandlerType* handler);
void _handleRequest(); void _handleRequest();
void _finalizeResponse(); void _finalizeResponse();
bool _parseRequest(ClientType& client); ClientFuture _parseRequest(ClientType& client);
void _parseArguments(const String& data); void _parseArguments(const String& data);
int _parseArgumentsPrivate(const String& data, std::function<void(String&,String&,const String&,int,int,int,int)> handler); int _parseArgumentsPrivate(const String& data, std::function<void(String&,String&,const String&,int,int,int,int)> handler);
bool _parseForm(ClientType& client, const String& boundary, uint32_t len); bool _parseForm(ClientType& client, const String& boundary, uint32_t len);
@ -261,8 +291,7 @@ protected:
String _sopaque; String _sopaque;
String _srealm; // Store the Auth realm between Calls String _srealm; // Store the Auth realm between Calls
HookFunction _hook;
}; };

View File

@ -25,13 +25,6 @@
#include "ESP8266WebServer.h" #include "ESP8266WebServer.h"
#include "detail/mimetable.h" #include "detail/mimetable.h"
//#define DEBUG_ESP_HTTP_SERVER
#ifdef DEBUG_ESP_PORT
#define DEBUG_OUTPUT DEBUG_ESP_PORT
#else
#define DEBUG_OUTPUT Serial
#endif
#ifndef WEBSERVER_MAX_POST_ARGS #ifndef WEBSERVER_MAX_POST_ARGS
#define WEBSERVER_MAX_POST_ARGS 32 #define WEBSERVER_MAX_POST_ARGS 32
#endif #endif
@ -61,17 +54,14 @@ static bool readBytesWithTimeout(typename ServerType::ClientType& client, size_t
} }
template <typename ServerType> template <typename ServerType>
bool ESP8266WebServerTemplate<ServerType>::_parseRequest(ClientType& client) { typename ESP8266WebServerTemplate<ServerType>::ClientFuture ESP8266WebServerTemplate<ServerType>::_parseRequest(ClientType& client) {
// Read the first line of HTTP request // Read the first line of HTTP request
String req = client.readStringUntil('\r'); String req = client.readStringUntil('\r');
#ifdef DEBUG_ESP_HTTP_SERVER DBGWS("request: %s\n", req.c_str());
DEBUG_OUTPUT.print("request: ");
DEBUG_OUTPUT.println(req);
#endif
client.readStringUntil('\n'); client.readStringUntil('\n');
//reset header value //reset header value
for (int i = 0; i < _headerKeysCount; ++i) { for (int i = 0; i < _headerKeysCount; ++i) {
_currentHeaders[i].value =String(); _currentHeaders[i].value.clear();
} }
// First line of HTTP request looks like "GET /path HTTP/1.1" // First line of HTTP request looks like "GET /path HTTP/1.1"
@ -79,10 +69,8 @@ bool ESP8266WebServerTemplate<ServerType>::_parseRequest(ClientType& client) {
int addr_start = req.indexOf(' '); int addr_start = req.indexOf(' ');
int addr_end = req.indexOf(' ', addr_start + 1); int addr_end = req.indexOf(' ', addr_start + 1);
if (addr_start == -1 || addr_end == -1) { if (addr_start == -1 || addr_end == -1) {
#ifdef DEBUG_ESP_HTTP_SERVER DBGWS("Invalid request\n");
DEBUG_OUTPUT.println("Invalid request"); return CLIENT_MUST_STOP;
#endif
return false;
} }
String methodStr = req.substring(0, addr_start); String methodStr = req.substring(0, addr_start);
@ -98,6 +86,13 @@ bool ESP8266WebServerTemplate<ServerType>::_parseRequest(ClientType& client) {
_currentUri = url; _currentUri = url;
_chunked = false; _chunked = false;
if (_hook)
{
auto whatNow = _hook(methodStr, url, &client, mime::getContentType);
if (whatNow != CLIENT_REQUEST_CAN_CONTINUE)
return whatNow;
}
HTTPMethod method = HTTP_GET; HTTPMethod method = HTTP_GET;
if (methodStr == F("HEAD")) { if (methodStr == F("HEAD")) {
method = HTTP_HEAD; method = HTTP_HEAD;
@ -117,14 +112,8 @@ bool ESP8266WebServerTemplate<ServerType>::_parseRequest(ClientType& client) {
_keepAlive = _currentVersion > 0; // Keep the connection alive by default _keepAlive = _currentVersion > 0; // Keep the connection alive by default
// if the protocol version is greater than HTTP 1.0 // if the protocol version is greater than HTTP 1.0
#ifdef DEBUG_ESP_HTTP_SERVER DBGWS("method: %s url: %s search: %s keepAlive=: %d\n",
DEBUG_OUTPUT.print("method: "); methodStr.c_str(), url.c_str(), searchStr.c_str(), _keepAlive);
DEBUG_OUTPUT.print(methodStr);
DEBUG_OUTPUT.print(" url: ");
DEBUG_OUTPUT.print(url);
DEBUG_OUTPUT.print(" search: ");
DEBUG_OUTPUT.println(searchStr);
#endif
//attach handler //attach handler
RequestHandlerType* handler; RequestHandlerType* handler;
@ -157,12 +146,7 @@ bool ESP8266WebServerTemplate<ServerType>::_parseRequest(ClientType& client) {
headerValue.trim(); headerValue.trim();
_collectHeader(headerName.c_str(),headerValue.c_str()); _collectHeader(headerName.c_str(),headerValue.c_str());
#ifdef DEBUG_ESP_HTTP_SERVER DBGWS("headerName: %s\nheaderValue: %s\n", headerName.c_str(), headerValue.c_str());
DEBUG_OUTPUT.print("headerName: ");
DEBUG_OUTPUT.println(headerName);
DEBUG_OUTPUT.print("headerValue: ");
DEBUG_OUTPUT.println(headerValue);
#endif
if (headerName.equalsIgnoreCase(FPSTR(Content_Type))){ if (headerName.equalsIgnoreCase(FPSTR(Content_Type))){
using namespace mime; using namespace mime;
@ -193,7 +177,7 @@ bool ESP8266WebServerTemplate<ServerType>::_parseRequest(ClientType& client) {
) )
) )
{ {
return false; return CLIENT_MUST_STOP;
} }
if (isEncoded) { if (isEncoded) {
@ -218,7 +202,7 @@ bool ESP8266WebServerTemplate<ServerType>::_parseRequest(ClientType& client) {
} else { // isForm is true } else { // isForm is true
// here: content is not yet read (plainBuf is still empty) // here: content is not yet read (plainBuf is still empty)
if (!_parseForm(client, boundaryStr, contentLength)) { if (!_parseForm(client, boundaryStr, contentLength)) {
return false; return CLIENT_MUST_STOP;
} }
} }
} else { } else {
@ -237,12 +221,7 @@ bool ESP8266WebServerTemplate<ServerType>::_parseRequest(ClientType& client) {
headerValue = req.substring(headerDiv + 2); headerValue = req.substring(headerDiv + 2);
_collectHeader(headerName.c_str(),headerValue.c_str()); _collectHeader(headerName.c_str(),headerValue.c_str());
#ifdef DEBUG_ESP_HTTP_SERVER DBGWS("headerName: %s\nheaderValue: %s\n", headerName.c_str(), headerValue.c_str());
DEBUG_OUTPUT.print(F("headerName: "));
DEBUG_OUTPUT.println(headerName);
DEBUG_OUTPUT.print(F("headerValue: "));
DEBUG_OUTPUT.println(headerValue);
#endif
if (headerName.equalsIgnoreCase(F("Host"))){ if (headerName.equalsIgnoreCase(F("Host"))){
_hostHeader = headerValue; _hostHeader = headerValue;
@ -255,19 +234,15 @@ bool ESP8266WebServerTemplate<ServerType>::_parseRequest(ClientType& client) {
client.flush(); client.flush();
#ifdef DEBUG_ESP_HTTP_SERVER #ifdef DEBUG_ESP_HTTP_SERVER
DEBUG_OUTPUT.print(F("Request: ")); DBGWS("Request: %s\nArguments: %s\nfinal list of key/value pairs:\n",
DEBUG_OUTPUT.println(url); url.c_str(), searchStr.c_str());
DEBUG_OUTPUT.print(F("Arguments: "));
DEBUG_OUTPUT.println(searchStr);
DEBUG_OUTPUT.println(F("final list of key/value pairs:"));
for (int i = 0; i < _currentArgCount; i++) for (int i = 0; i < _currentArgCount; i++)
DEBUG_OUTPUT.printf(" key:'%s' value:'%s'\r\n", DBGWS(" key:'%s' value:'%s'\r\n",
_currentArgs[i].key.c_str(), _currentArgs[i].key.c_str(),
_currentArgs[i].value.c_str()); _currentArgs[i].value.c_str());
#endif #endif
return true; return CLIENT_REQUEST_CAN_CONTINUE;
} }
template <typename ServerType> template <typename ServerType>
@ -316,10 +291,7 @@ void ESP8266WebServerTemplate<ServerType>::_parseArguments(const String& data) {
template <typename ServerType> template <typename ServerType>
int ESP8266WebServerTemplate<ServerType>::_parseArgumentsPrivate(const String& data, std::function<void(String&,String&,const String&,int,int,int,int)> handler) { int ESP8266WebServerTemplate<ServerType>::_parseArgumentsPrivate(const String& data, std::function<void(String&,String&,const String&,int,int,int,int)> handler) {
#ifdef DEBUG_ESP_HTTP_SERVER DBGWS("args: %s\n", data.c_str());
DEBUG_OUTPUT.print("args: ");
DEBUG_OUTPUT.println(data);
#endif
size_t pos = 0; size_t pos = 0;
int arg_total = 0; int arg_total = 0;
@ -357,11 +329,7 @@ int ESP8266WebServerTemplate<ServerType>::_parseArgumentsPrivate(const String& d
break; break;
} }
#ifdef DEBUG_ESP_HTTP_SERVER DBGWS("args count: %d\n", (int)arg_total);
DEBUG_OUTPUT.print("args count: ");
DEBUG_OUTPUT.println(arg_total);
#endif
return arg_total; return arg_total;
} }
@ -390,12 +358,7 @@ uint8_t ESP8266WebServerTemplate<ServerType>::_uploadReadByte(ClientType& client
template <typename ServerType> template <typename ServerType>
bool ESP8266WebServerTemplate<ServerType>::_parseForm(ClientType& client, const String& boundary, uint32_t len){ bool ESP8266WebServerTemplate<ServerType>::_parseForm(ClientType& client, const String& boundary, uint32_t len){
(void) len; (void) len;
#ifdef DEBUG_ESP_HTTP_SERVER DBGWS("Parse Form: Boundary: '%s' Length: %d\n", boundary.c_str(), (int)len);
DEBUG_OUTPUT.print("Parse Form: Boundary: ");
DEBUG_OUTPUT.print(boundary);
DEBUG_OUTPUT.print(" Length: ");
DEBUG_OUTPUT.println(len);
#endif
String line; String line;
int retry = 0; int retry = 0;
do { do {
@ -429,18 +392,12 @@ bool ESP8266WebServerTemplate<ServerType>::_parseForm(ClientType& client, const
argFilename = argName.substring(nameStart+2, argName.length() - 1); argFilename = argName.substring(nameStart+2, argName.length() - 1);
argName = argName.substring(0, argName.indexOf('"')); argName = argName.substring(0, argName.indexOf('"'));
argIsFile = true; argIsFile = true;
#ifdef DEBUG_ESP_HTTP_SERVER DBGWS("PostArg FileName: %s\n", argFilename.c_str());
DEBUG_OUTPUT.print("PostArg FileName: ");
DEBUG_OUTPUT.println(argFilename);
#endif
//use GET to set the filename if uploading using blob //use GET to set the filename if uploading using blob
if (argFilename == F("blob") && hasArg(FPSTR(filename))) if (argFilename == F("blob") && hasArg(FPSTR(filename)))
argFilename = arg(FPSTR(filename)); argFilename = arg(FPSTR(filename));
} }
#ifdef DEBUG_ESP_HTTP_SERVER DBGWS("PostArg Name: %s\n", argName.c_str());
DEBUG_OUTPUT.print("PostArg Name: ");
DEBUG_OUTPUT.println(argName);
#endif
using namespace mime; using namespace mime;
argType = FPSTR(mimeTable[txt].mimeType); argType = FPSTR(mimeTable[txt].mimeType);
line = client.readStringUntil('\r'); line = client.readStringUntil('\r');
@ -451,10 +408,7 @@ bool ESP8266WebServerTemplate<ServerType>::_parseForm(ClientType& client, const
client.readStringUntil('\r'); client.readStringUntil('\r');
client.readStringUntil('\n'); client.readStringUntil('\n');
} }
#ifdef DEBUG_ESP_HTTP_SERVER DBGWS("PostArg Type: %s\n", argType.c_str());
DEBUG_OUTPUT.print("PostArg Type: ");
DEBUG_OUTPUT.println(argType);
#endif
if (!argIsFile){ if (!argIsFile){
while(1){ while(1){
line = client.readStringUntil('\r'); line = client.readStringUntil('\r');
@ -463,20 +417,14 @@ bool ESP8266WebServerTemplate<ServerType>::_parseForm(ClientType& client, const
if (argValue.length() > 0) argValue += '\n'; if (argValue.length() > 0) argValue += '\n';
argValue += line; argValue += line;
} }
#ifdef DEBUG_ESP_HTTP_SERVER DBGWS("PostArg Value: %s\n\n", argValue.c_str());
DEBUG_OUTPUT.print("PostArg Value: ");
DEBUG_OUTPUT.println(argValue);
DEBUG_OUTPUT.println();
#endif
RequestArgument& arg = _postArgs[_postArgsLen++]; RequestArgument& arg = _postArgs[_postArgsLen++];
arg.key = argName; arg.key = argName;
arg.value = argValue; arg.value = argValue;
if (line == ("--"+boundary+"--")){ if (line == ("--"+boundary+"--")){
#ifdef DEBUG_ESP_HTTP_SERVER DBGWS("Done Parsing POST\n");
DEBUG_OUTPUT.println("Done Parsing POST");
#endif
break; break;
} }
} else { } else {
@ -488,12 +436,7 @@ bool ESP8266WebServerTemplate<ServerType>::_parseForm(ClientType& client, const
_currentUpload->totalSize = 0; _currentUpload->totalSize = 0;
_currentUpload->currentSize = 0; _currentUpload->currentSize = 0;
_currentUpload->contentLength = len; _currentUpload->contentLength = len;
#ifdef DEBUG_ESP_HTTP_SERVER DBGWS("Start File: %s Type: %s\n", _currentUpload->filename.c_str(), _currentUpload->type.c_str());
DEBUG_OUTPUT.print("Start File: ");
DEBUG_OUTPUT.print(_currentUpload->filename);
DEBUG_OUTPUT.print(" Type: ");
DEBUG_OUTPUT.println(_currentUpload->type);
#endif
if(_currentHandler && _currentHandler->canUpload(_currentUri)) if(_currentHandler && _currentHandler->canUpload(_currentUri))
_currentHandler->upload(*this, _currentUri, *_currentUpload); _currentHandler->upload(*this, _currentUri, *_currentUpload);
_currentUpload->status = UPLOAD_FILE_WRITE; _currentUpload->status = UPLOAD_FILE_WRITE;
@ -537,20 +480,14 @@ readfile:
_currentUpload->status = UPLOAD_FILE_END; _currentUpload->status = UPLOAD_FILE_END;
if(_currentHandler && _currentHandler->canUpload(_currentUri)) if(_currentHandler && _currentHandler->canUpload(_currentUri))
_currentHandler->upload(*this, _currentUri, *_currentUpload); _currentHandler->upload(*this, _currentUri, *_currentUpload);
#ifdef DEBUG_ESP_HTTP_SERVER DBGWS("End File: %s Type: %s Size: %d\n",
DEBUG_OUTPUT.print("End File: "); _currentUpload->filename.c_str(),
DEBUG_OUTPUT.print(_currentUpload->filename); _currentUpload->type.c_str(),
DEBUG_OUTPUT.print(" Type: "); (int)_currentUpload->totalSize);
DEBUG_OUTPUT.print(_currentUpload->type);
DEBUG_OUTPUT.print(" Size: ");
DEBUG_OUTPUT.println(_currentUpload->totalSize);
#endif
line = client.readStringUntil(0x0D); line = client.readStringUntil(0x0D);
client.readStringUntil(0x0A); client.readStringUntil(0x0A);
if (line == "--"){ if (line == "--"){
#ifdef DEBUG_ESP_HTTP_SERVER DBGWS("Done Parsing POST\n");
DEBUG_OUTPUT.println("Done Parsing POST");
#endif
break; break;
} }
continue; continue;
@ -598,10 +535,7 @@ readfile:
} }
return true; return true;
} }
#ifdef DEBUG_ESP_HTTP_SERVER DBGWS("Error: line: %s\n", line.c_str());
DEBUG_OUTPUT.print("Error: line: ");
DEBUG_OUTPUT.println(line);
#endif
return false; return false;
} }