Files
EMS-ESP32/lib/ESPAsyncWebServer/src/ESPAsyncWebServer.h
2024-06-04 21:19:34 +02:00

619 lines
22 KiB
C++

/*
Asynchronous WebServer library for Espressif MCUs
Copyright (c) 2016 Hristo Gochkov. All rights reserved.
This file is part of the esp8266 core for Arduino environment.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef _ESPAsyncWebServer_H_
#define _ESPAsyncWebServer_H_
#include "Arduino.h"
#include <functional>
#include <list>
#include <vector>
#include "FS.h"
#include <ArduinoJson.h> // added by proddy for EMS-ESP
#include "StringArray.h"
#ifdef ESP32
#include <WiFi.h>
#include <AsyncTCP.h>
#elif defined(ESP8266)
#include <ESP8266WiFi.h>
#include <ESPAsyncTCP.h>
#else
#error Platform not supported
#endif
#define ASYNCWEBSERVER_VERSION "2.6.1"
#define ASYNCWEBSERVER_VERSION_MAJOR 2
#define ASYNCWEBSERVER_VERSION_MINOR 6
#define ASYNCWEBSERVER_VERSION_REVISION 1
#define ASYNCWEBSERVER_FORK_mathieucarbou
#ifdef ASYNCWEBSERVER_REGEX
#define ASYNCWEBSERVER_REGEX_ATTRIBUTE
#else
#define ASYNCWEBSERVER_REGEX_ATTRIBUTE __attribute__((warning("ASYNCWEBSERVER_REGEX not defined")))
#endif
class AsyncWebServer;
class AsyncWebServerRequest;
class AsyncWebServerResponse;
class AsyncWebHeader;
class AsyncWebParameter;
class AsyncWebRewrite;
class AsyncWebHandler;
class AsyncStaticWebHandler;
class AsyncCallbackWebHandler;
class AsyncResponseStream;
#ifndef WEBSERVER_H
typedef enum {
HTTP_GET = 0b00000001,
HTTP_POST = 0b00000010,
HTTP_DELETE = 0b00000100,
HTTP_PUT = 0b00001000,
HTTP_PATCH = 0b00010000,
HTTP_HEAD = 0b00100000,
HTTP_OPTIONS = 0b01000000,
HTTP_ANY = 0b01111111,
} WebRequestMethod;
#endif
#ifndef HAVE_FS_FILE_OPEN_MODE
namespace fs {
class FileOpenMode {
public:
static const char * read;
static const char * write;
static const char * append;
};
}; // namespace fs
#else
#include "FileOpenMode.h"
#endif
//if this value is returned when asked for data, packet will not be sent and you will be asked for data again
#define RESPONSE_TRY_AGAIN 0xFFFFFFFF
typedef uint8_t WebRequestMethodComposite;
typedef std::function<void(void)> ArDisconnectHandler;
/*
* PARAMETER :: Chainable object to hold GET/POST and FILE parameters
* */
class AsyncWebParameter {
private:
String _name;
String _value;
size_t _size;
bool _isForm;
bool _isFile;
public:
AsyncWebParameter(const String & name, const String & value, bool form = false, bool file = false, size_t size = 0)
: _name(name)
, _value(value)
, _size(size)
, _isForm(form)
, _isFile(file) {
}
const String & name() const {
return _name;
}
const String & value() const {
return _value;
}
size_t size() const {
return _size;
}
bool isPost() const {
return _isForm;
}
bool isFile() const {
return _isFile;
}
};
/*
* HEADER :: Chainable object to hold the headers
* */
class AsyncWebHeader {
private:
String _name;
String _value;
public:
AsyncWebHeader() = default;
AsyncWebHeader(const AsyncWebHeader &) = default;
AsyncWebHeader(const String & name, const String & value)
: _name(name)
, _value(value) {
}
AsyncWebHeader(const String & data)
: _name()
, _value() {
if (!data)
return;
int index = data.indexOf(':');
if (index < 0)
return;
_name = data.substring(0, index);
_value = data.substring(index + 2);
}
AsyncWebHeader & operator=(const AsyncWebHeader &) = default;
const String & name() const {
return _name;
}
const String & value() const {
return _value;
}
String toString() const {
return _name + F(": ") + _value + F("\r\n");
}
};
/*
* REQUEST :: Each incoming Client is wrapped inside a Request and both live together until disconnect
* */
typedef enum { RCT_NOT_USED = -1, RCT_DEFAULT = 0, RCT_HTTP, RCT_WS, RCT_EVENT, RCT_MAX } RequestedConnectionType;
typedef std::function<size_t(uint8_t *, size_t, size_t)> AwsResponseFiller;
typedef std::function<String(const String &)> AwsTemplateProcessor;
class AsyncWebServerRequest {
using File = fs::File;
using FS = fs::FS;
friend class AsyncWebServer;
friend class AsyncCallbackWebHandler;
private:
AsyncClient * _client;
AsyncWebServer * _server;
AsyncWebHandler * _handler;
AsyncWebServerResponse * _response;
std::vector<String> _interestingHeaders;
ArDisconnectHandler _onDisconnectfn;
String _temp;
uint8_t _parseState;
uint8_t _version;
WebRequestMethodComposite _method;
String _url;
String _host;
String _contentType;
String _boundary;
String _authorization;
RequestedConnectionType _reqconntype;
void _removeNotInterestingHeaders();
bool _isDigest;
bool _isMultipart;
bool _isPlainPost;
bool _expectingContinue;
size_t _contentLength;
size_t _parsedLength;
std::list<AsyncWebHeader> _headers;
LinkedList<AsyncWebParameter *> _params;
std::vector<String> _pathParams;
uint8_t _multiParseState;
uint8_t _boundaryPosition;
size_t _itemStartIndex;
size_t _itemSize;
String _itemName;
String _itemFilename;
String _itemType;
String _itemValue;
uint8_t * _itemBuffer;
size_t _itemBufferIndex;
bool _itemIsFile;
void _onPoll();
void _onAck(size_t len, uint32_t time);
void _onError(int8_t error);
void _onTimeout(uint32_t time);
void _onDisconnect();
void _onData(void * buf, size_t len);
void _addParam(AsyncWebParameter *);
void _addPathParam(const char * param);
bool _parseReqHead();
bool _parseReqHeader();
void _parseLine();
void _parsePlainPostChar(uint8_t data);
void _parseMultipartPostByte(uint8_t data, bool last);
void _addGetParams(const String & params);
void _handleUploadStart();
void _handleUploadByte(uint8_t data, bool last);
void _handleUploadEnd();
public:
File _tempFile;
void * _tempObject;
AsyncWebServerRequest(AsyncWebServer *, AsyncClient *);
~AsyncWebServerRequest();
AsyncClient * client() {
return _client;
}
uint8_t version() const {
return _version;
}
WebRequestMethodComposite method() const {
return _method;
}
const String & url() const {
return _url;
}
const String & host() const {
return _host;
}
const String & contentType() const {
return _contentType;
}
size_t contentLength() const {
return _contentLength;
}
bool multipart() const {
return _isMultipart;
}
const __FlashStringHelper * methodToString() const;
const __FlashStringHelper * requestedConnTypeToString() const;
RequestedConnectionType requestedConnType() const {
return _reqconntype;
}
bool isExpectedRequestedConnType(RequestedConnectionType erct1, RequestedConnectionType erct2 = RCT_NOT_USED, RequestedConnectionType erct3 = RCT_NOT_USED);
void onDisconnect(ArDisconnectHandler fn);
//hash is the string representation of:
// base64(user:pass) for basic or
// user:realm:md5(user:realm:pass) for digest
bool authenticate(const char * hash);
bool authenticate(const char * username, const char * password, const char * realm = NULL, bool passwordIsHash = false);
void requestAuthentication(const char * realm = NULL, bool isDigest = true);
void setHandler(AsyncWebHandler * handler) {
_handler = handler;
}
void addInterestingHeader(const String & name);
void redirect(const String & url);
void send(AsyncWebServerResponse * response);
void send(int code, const String & contentType = String(), const String & content = String());
void send(FS & fs, const String & path, const String & contentType = String(), bool download = false, AwsTemplateProcessor callback = nullptr);
void send(File content, const String & path, const String & contentType = String(), bool download = false, AwsTemplateProcessor callback = nullptr);
void send(Stream & stream, const String & contentType, size_t len, AwsTemplateProcessor callback = nullptr);
void send(const String & contentType, size_t len, AwsResponseFiller callback, AwsTemplateProcessor templateCallback = nullptr);
void sendChunked(const String & contentType, AwsResponseFiller callback, AwsTemplateProcessor templateCallback = nullptr);
void send_P(int code, const String & contentType, const uint8_t * content, size_t len, AwsTemplateProcessor callback = nullptr);
void send_P(int code, const String & contentType, PGM_P content, AwsTemplateProcessor callback = nullptr);
AsyncWebServerResponse * beginResponse(int code, const String & contentType = String(), const String & content = String());
AsyncWebServerResponse *
beginResponse(FS & fs, const String & path, const String & contentType = String(), bool download = false, AwsTemplateProcessor callback = nullptr);
AsyncWebServerResponse *
beginResponse(File content, const String & path, const String & contentType = String(), bool download = false, AwsTemplateProcessor callback = nullptr);
AsyncWebServerResponse * beginResponse(Stream & stream, const String & contentType, size_t len, AwsTemplateProcessor callback = nullptr);
AsyncWebServerResponse * beginResponse(const String & contentType, size_t len, AwsResponseFiller callback, AwsTemplateProcessor templateCallback = nullptr);
AsyncWebServerResponse * beginChunkedResponse(const String & contentType, AwsResponseFiller callback, AwsTemplateProcessor templateCallback = nullptr);
AsyncResponseStream * beginResponseStream(const String & contentType, size_t bufferSize = 1460);
AsyncWebServerResponse * beginResponse_P(int code, const String & contentType, const uint8_t * content, size_t len, AwsTemplateProcessor callback = nullptr);
AsyncWebServerResponse * beginResponse_P(int code, const String & contentType, PGM_P content, AwsTemplateProcessor callback = nullptr);
// added by proddy for EMS-ESP
AsyncWebServerResponse * beginResponse(const String & contentType, const uint8_t * content, size_t len);
size_t headers() const; // get header count
bool hasHeader(const String & name) const; // check if header exists
bool hasHeader(const __FlashStringHelper * data) const; // check if header exists
AsyncWebHeader * getHeader(const String & name);
const AsyncWebHeader * getHeader(const String & name) const;
AsyncWebHeader * getHeader(const __FlashStringHelper * data);
const AsyncWebHeader * getHeader(const __FlashStringHelper * data) const;
AsyncWebHeader * getHeader(size_t num);
const AsyncWebHeader * getHeader(size_t num) const;
size_t params() const; // get arguments count
bool hasParam(const String & name, bool post = false, bool file = false) const;
bool hasParam(const __FlashStringHelper * data, bool post = false, bool file = false) const;
AsyncWebParameter * getParam(const String & name, bool post = false, bool file = false) const;
AsyncWebParameter * getParam(const __FlashStringHelper * data, bool post, bool file) const;
AsyncWebParameter * getParam(size_t num) const;
size_t args() const {
return params();
} // get arguments count
const String & arg(const String & name) const; // get request argument value by name
const String & arg(const __FlashStringHelper * data) const; // get request argument value by F(name)
const String & arg(size_t i) const; // get request argument value by number
const String & argName(size_t i) const; // get request argument name by number
bool hasArg(const char * name) const; // check if argument exists
bool hasArg(const __FlashStringHelper * data) const; // check if F(argument) exists
const String & ASYNCWEBSERVER_REGEX_ATTRIBUTE pathArg(size_t i) const;
const String & header(const char * name) const; // get request header value by name
const String & header(const __FlashStringHelper * data) const; // get request header value by F(name)
const String & header(size_t i) const; // get request header value by number
const String & headerName(size_t i) const; // get request header name by number
String urlDecode(const String & text) const;
};
/*
* FILTER :: Callback to filter AsyncWebRewrite and AsyncWebHandler (done by the Server)
* */
typedef std::function<bool(AsyncWebServerRequest * request)> ArRequestFilterFunction;
bool ON_STA_FILTER(AsyncWebServerRequest * request);
bool ON_AP_FILTER(AsyncWebServerRequest * request);
/*
* REWRITE :: One instance can be handle any Request (done by the Server)
* */
class AsyncWebRewrite {
protected:
String _from;
String _toUrl;
String _params;
ArRequestFilterFunction _filter;
public:
AsyncWebRewrite(const char * from, const char * to)
: _from(from)
, _toUrl(to)
, _params(String())
, _filter(NULL) {
int index = _toUrl.indexOf('?');
if (index > 0) {
_params = _toUrl.substring(index + 1);
_toUrl = _toUrl.substring(0, index);
}
}
virtual ~AsyncWebRewrite() {
}
AsyncWebRewrite & setFilter(ArRequestFilterFunction fn) {
_filter = fn;
return *this;
}
bool filter(AsyncWebServerRequest * request) const {
return _filter == NULL || _filter(request);
}
const String & from(void) const {
return _from;
}
const String & toUrl(void) const {
return _toUrl;
}
const String & params(void) const {
return _params;
}
virtual bool match(AsyncWebServerRequest * request) {
return from() == request->url() && filter(request);
}
};
/*
* HANDLER :: One instance can be attached to any Request (done by the Server)
* */
class AsyncWebHandler {
protected:
ArRequestFilterFunction _filter;
String _username;
String _password;
public:
AsyncWebHandler()
: _username("")
, _password("") {
}
AsyncWebHandler & setFilter(ArRequestFilterFunction fn) {
_filter = fn;
return *this;
}
AsyncWebHandler & setAuthentication(const String & username, const String & password) {
_username = username;
_password = password;
return *this;
};
AsyncWebHandler & setAuthentication(const char * username, const char * password) {
_username = String(username);
_password = String(password);
return *this;
};
bool filter(AsyncWebServerRequest * request) {
return _filter == NULL || _filter(request);
}
virtual ~AsyncWebHandler() {
}
virtual bool canHandle(AsyncWebServerRequest * request __attribute__((unused))) {
return false;
}
virtual void handleRequest(AsyncWebServerRequest * request __attribute__((unused))) {
}
virtual void handleUpload(AsyncWebServerRequest * request __attribute__((unused)),
const String & filename __attribute__((unused)),
size_t index __attribute__((unused)),
uint8_t * data __attribute__((unused)),
size_t len __attribute__((unused)),
bool final __attribute__((unused))) {
}
virtual void handleBody(AsyncWebServerRequest * request __attribute__((unused)),
uint8_t * data __attribute__((unused)),
size_t len __attribute__((unused)),
size_t index __attribute__((unused)),
size_t total __attribute__((unused))) {
}
virtual bool isRequestHandlerTrivial() {
return true;
}
};
/*
* RESPONSE :: One instance is created for each Request (attached by the Handler)
* */
typedef enum { RESPONSE_SETUP, RESPONSE_HEADERS, RESPONSE_CONTENT, RESPONSE_WAIT_ACK, RESPONSE_END, RESPONSE_FAILED } WebResponseState;
class AsyncWebServerResponse {
protected:
int _code;
std::list<AsyncWebHeader> _headers;
String _contentType;
size_t _contentLength;
bool _sendContentLength;
bool _chunked;
size_t _headLength;
size_t _sentLength;
size_t _ackedLength;
size_t _writtenLength;
WebResponseState _state;
const char * _responseCodeToString(int code);
public:
static const __FlashStringHelper * responseCodeToString(int code);
public:
AsyncWebServerResponse();
virtual ~AsyncWebServerResponse();
virtual void setCode(int code);
virtual void setContentLength(size_t len);
virtual void setContentType(const String & type);
virtual void addHeader(const String & name, const String & value);
virtual String _assembleHead(uint8_t version);
virtual bool _started() const;
virtual bool _finished() const;
virtual bool _failed() const;
virtual bool _sourceValid() const;
virtual void _respond(AsyncWebServerRequest * request);
virtual size_t _ack(AsyncWebServerRequest * request, size_t len, uint32_t time);
};
/*
* SERVER :: One instance
* */
typedef std::function<void(AsyncWebServerRequest * request)> ArRequestHandlerFunction;
typedef std::function<void(AsyncWebServerRequest * request, const String & filename, size_t index, uint8_t * data, size_t len, bool final)> ArUploadHandlerFunction;
typedef std::function<void(AsyncWebServerRequest * request, uint8_t * data, size_t len, size_t index, size_t total)> ArBodyHandlerFunction;
typedef std::function<void(AsyncWebServerRequest * request, JsonVariant json)> ArJsonRequestHandlerFunction; // added by proddy for EMS-ESP
class AsyncWebServer {
protected:
AsyncServer _server;
LinkedList<AsyncWebRewrite *> _rewrites;
LinkedList<AsyncWebHandler *> _handlers;
AsyncCallbackWebHandler * _catchAllHandler;
public:
AsyncWebServer(uint16_t port);
~AsyncWebServer();
void begin();
void end();
#if ASYNC_TCP_SSL_ENABLED
void onSslFileRequest(AcSSlFileHandler cb, void * arg);
void beginSecure(const char * cert, const char * private_key_file, const char * password);
#endif
AsyncWebRewrite & addRewrite(AsyncWebRewrite * rewrite);
bool removeRewrite(AsyncWebRewrite * rewrite);
AsyncWebRewrite & rewrite(const char * from, const char * to);
AsyncWebHandler & addHandler(AsyncWebHandler * handler);
bool removeHandler(AsyncWebHandler * handler);
AsyncCallbackWebHandler & on(const char * uri, ArRequestHandlerFunction onRequest);
AsyncCallbackWebHandler & on(const char * uri, WebRequestMethodComposite method, ArRequestHandlerFunction onRequest);
AsyncCallbackWebHandler & on(const char * uri, WebRequestMethodComposite method, ArRequestHandlerFunction onRequest, ArUploadHandlerFunction onUpload);
AsyncCallbackWebHandler &
on(const char * uri, WebRequestMethodComposite method, ArRequestHandlerFunction onRequest, ArUploadHandlerFunction onUpload, ArBodyHandlerFunction onBody);
void on(const char * uri, ArJsonRequestHandlerFunction onRequest); // added by proddy for EMS-ESP
AsyncStaticWebHandler & serveStatic(const char * uri, fs::FS & fs, const char * path, const char * cache_control = NULL);
void onNotFound(ArRequestHandlerFunction fn); //called when handler is not assigned
void onFileUpload(ArUploadHandlerFunction fn); //handle file uploads
void onRequestBody(ArBodyHandlerFunction fn); //handle posts with plain body content (JSON often transmitted this way as a request)
void reset(); //remove all writers and handlers, with onNotFound/onFileUpload/onRequestBody
void _handleDisconnect(AsyncWebServerRequest * request);
void _attachHandler(AsyncWebServerRequest * request);
void _rewriteRequest(AsyncWebServerRequest * request);
};
class DefaultHeaders {
using headers_t = std::list<AsyncWebHeader>;
headers_t _headers;
public:
DefaultHeaders() = default;
using ConstIterator = headers_t::const_iterator;
void addHeader(const String & name, const String & value) {
_headers.emplace_back(name, value);
}
ConstIterator begin() const {
return _headers.begin();
}
ConstIterator end() const {
return _headers.end();
}
DefaultHeaders(DefaultHeaders const &) = delete;
DefaultHeaders & operator=(DefaultHeaders const &) = delete;
static DefaultHeaders & Instance() {
static DefaultHeaders instance;
return instance;
}
};
#include "WebResponseImpl.h"
#include "WebHandlerImpl.h"
#include "AsyncWebSocket.h"
#include "AsyncEventSource.h"
#endif /* _AsyncWebServer_H_ */