1
0
mirror of https://github.com/esp8266/Arduino.git synced 2025-07-23 08:45:22 +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
5 changed files with 187 additions and 144 deletions

View File

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