ESPAsyncWebServer/src/ESPAsyncWebServer.h

383 lines
13 KiB
C
Raw Normal View History

/*
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
*/
2015-12-19 09:50:42 -08:00
#ifndef _ESPAsyncWebServer_H_
#define _ESPAsyncWebServer_H_
2015-12-19 08:53:33 -08:00
#include "Arduino.h"
#include <functional>
#include <ESPAsyncTCP.h>
2015-12-22 02:42:07 -08:00
#include "FS.h"
2015-12-19 08:53:33 -08:00
#include "StringArray.h"
#if defined(ESP31B)
#include <ESP31BWiFi.h>
#elif defined(ESP8266)
#include <ESP8266WiFi.h>
#else
#error Platform not supported
#endif
2016-01-27 13:42:16 -08:00
#define DEBUGF(...) //Serial.printf(__VA_ARGS__)
2016-01-27 12:16:21 -08:00
2015-12-19 08:53:33 -08:00
class AsyncWebServer;
class AsyncWebServerRequest;
class AsyncWebServerResponse;
class AsyncWebHeader;
class AsyncWebParameter;
class AsyncWebRewrite;
2015-12-19 08:53:33 -08:00
class AsyncWebHandler;
class AsyncStaticWebHandler;
class AsyncCallbackWebHandler;
class AsyncResponseStream;
2015-12-19 08:53:33 -08:00
typedef enum {
HTTP_ANY, HTTP_GET, HTTP_POST, HTTP_DELETE, HTTP_PUT, HTTP_PATCH, HTTP_HEAD, HTTP_OPTIONS
} WebRequestMethod;
/*
* 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 *next;
AsyncWebParameter(String name, String value, bool form=false, bool file=false, size_t size=0): _name(name), _value(value), _size(size), _isForm(form), _isFile(file), next(NULL){}
String name(){ return _name; }
String value(){ return _value; }
size_t size(){ return _size; }
bool isPost(){ return _isForm; }
bool isFile(){ return _isFile; }
};
/*
* HEADER :: Chainable object to hold the headers
* */
class AsyncWebHeader {
private:
String _name;
String _value;
public:
AsyncWebHeader *next;
AsyncWebHeader(String name, String value): _name(name), _value(value), next(NULL){}
AsyncWebHeader(String data): _name(), _value(), next(NULL){
if(!data) return;
int index = data.indexOf(':');
if (index < 0) return;
_name = data.substring(0, index);
_value = data.substring(index + 2);
2015-12-19 08:53:33 -08:00
}
~AsyncWebHeader(){}
String name(){ return _name; }
String value(){ return _value; }
String toString(){ return String(_name+": "+_value+"\r\n"); }
};
/*
* REQUEST :: Each incoming Client is wrapped inside a Request and both live together until disconnect
* */
typedef std::function<size_t(uint8_t*, size_t, size_t)> AwsResponseFiller;
2015-12-19 08:53:33 -08:00
class AsyncWebServerRequest {
friend class AsyncWebServer;
2015-12-19 08:53:33 -08:00
private:
AsyncClient* _client;
AsyncWebServer* _server;
AsyncWebHandler* _handler;
AsyncWebServerResponse* _response;
StringArray* _interestingHeaders;
String _temp;
uint8_t _parseState;
uint8_t _version;
2015-12-19 08:53:33 -08:00
WebRequestMethod _method;
String _url;
String _host;
String _contentType;
String _boundary;
String _authorization;
bool _isMultipart;
bool _isPlainPost;
bool _expectingContinue;
size_t _contentLength;
size_t _parsedLength;
AsyncWebHeader *_headers;
AsyncWebParameter *_params;
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);
2015-12-22 02:42:07 -08:00
void _onError(int8_t error);
2015-12-19 08:53:33 -08:00
void _onTimeout(uint32_t time);
void _onDisconnect();
void _onData(void *buf, size_t len);
void _addParam(AsyncWebParameter*);
bool _parseReqHead();
bool _parseReqHeader();
void _parseLine();
void _parsePlainPostChar(uint8_t data);
void _parseMultipartPostByte(uint8_t data, bool last);
void _addGetParams(String params);
2015-12-19 08:53:33 -08:00
void _handleUploadStart();
void _handleUploadByte(uint8_t data, bool last);
void _handleUploadEnd();
public:
File _tempFile;
void *_tempObject;
AsyncWebServerRequest *next;
2015-12-19 08:53:33 -08:00
AsyncWebServerRequest(AsyncWebServer*, AsyncClient*);
~AsyncWebServerRequest();
AsyncClient* client(){ return _client; }
uint8_t version(){ return _version; }
2015-12-19 08:53:33 -08:00
WebRequestMethod method(){ return _method; }
String url(){ return _url; }
String host(){ return _host; }
String contentType(){ return _contentType; }
size_t contentLength(){ return _contentLength; }
bool multipart(){ return _isMultipart; }
const char * methodToString();
2015-12-19 08:53:33 -08:00
bool authenticate(const char * username, const char * password);
bool authenticate(const char * hash);
void requestAuthentication();
void setHandler(AsyncWebHandler *handler){ _handler = handler; }
void addInterestingHeader(String name);
2016-06-26 06:20:21 -07:00
void redirect(String url);
2015-12-19 08:53:33 -08:00
void send(AsyncWebServerResponse *response);
void send(int code, String contentType=String(), String content=String());
void send(FS &fs, String path, String contentType=String(), bool download=false);
void send(File content, String path, String contentType=String(), bool download=false);
2015-12-19 08:53:33 -08:00
void send(Stream &stream, String contentType, size_t len);
void send(String contentType, size_t len, AwsResponseFiller callback);
2016-01-27 09:55:32 -08:00
void sendChunked(String contentType, AwsResponseFiller callback);
2015-12-19 08:53:33 -08:00
AsyncWebServerResponse *beginResponse(int code, String contentType=String(), String content=String());
AsyncWebServerResponse *beginResponse(FS &fs, String path, String contentType=String(), bool download=false);
AsyncWebServerResponse *beginResponse(File content, String path, String contentType=String(), bool download=false);
2015-12-19 08:53:33 -08:00
AsyncWebServerResponse *beginResponse(Stream &stream, String contentType, size_t len);
AsyncWebServerResponse *beginResponse(String contentType, size_t len, AwsResponseFiller callback);
AsyncWebServerResponse *beginChunkedResponse(String contentType, AwsResponseFiller callback);
AsyncResponseStream *beginResponseStream(String contentType, size_t bufferSize=1460);
2015-12-19 08:53:33 -08:00
int headers(); // get header count
bool hasHeader(String name);
AsyncWebHeader* getHeader(String name);
AsyncWebHeader* getHeader(int num);
int params(); // get arguments count
bool hasParam(String name, bool post=false, bool file=false);
AsyncWebParameter* getParam(String name, bool post=false, bool file=false);
AsyncWebParameter* getParam(int num);
int args(){ return params(); } // get arguments count
String arg(const char* name); // get request argument value by name
String arg(int i); // get request argument value by number
String argName(int i); // get request argument name by number
bool hasArg(const char* name); // check if argument exists
String header(const char* name); // get request header value by name
String header(int i); // get request header value by number
String headerName(int i); // get request header name by number
bool hasHeader(const char* name); // check if header exists
2016-01-22 02:58:44 -08:00
String urlDecode(const String& text);
2015-12-19 08:53:33 -08:00
};
/*
* FILTER :: Callback to filter AsyncWebRewrite and AsyncWebHandler (done by the Server)
* */
typedef std::function<bool(AsyncWebServerRequest *request)> ArRequestFilterFunction;
static bool ON_STA_FILTER(AsyncWebServerRequest *request) {
return WiFi.localIP() == request->client()->localIP();
}
static bool ON_AP_FILTER(AsyncWebServerRequest *request) {
return WiFi.localIP() != request->client()->localIP();
}
/*
* 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* next;
AsyncWebRewrite(const char* from, const char* to): _from(from), _toUrl(to), _params(String()), _filter(NULL), next(NULL){
int index = _toUrl.indexOf('?');
if (index > 0) {
_params = _toUrl.substring(index +1);
_toUrl = _toUrl.substring(0, index);
}
}
AsyncWebRewrite& setFilter(ArRequestFilterFunction fn) { _filter = fn; }
bool filter(AsyncWebServerRequest *request){ return _filter == NULL || _filter(request); }
String from(void) { return _from; }
String toUrl(void) { return _toUrl; }
String params(void) { return _params; }
};
2015-12-19 08:53:33 -08:00
/*
* HANDLER :: One instance can be attached to any Request (done by the Server)
* */
class AsyncWebHandler {
protected:
ArRequestFilterFunction _filter;
2015-12-19 08:53:33 -08:00
public:
AsyncWebHandler* next;
AsyncWebHandler(): next(NULL){}
AsyncWebHandler& setFilter(ArRequestFilterFunction fn) { _filter = fn; }
bool filter(AsyncWebServerRequest *request){ return _filter == NULL || _filter(request); }
2015-12-19 08:53:33 -08:00
virtual ~AsyncWebHandler(){}
virtual bool canHandle(AsyncWebServerRequest *request){ return false; }
virtual void handleRequest(AsyncWebServerRequest *request){}
virtual void handleUpload(AsyncWebServerRequest *request, String filename, size_t index, uint8_t *data, size_t len, bool final){}
virtual void handleBody(AsyncWebServerRequest *request, uint8_t *data, size_t len, size_t index, size_t total){}
};
/*
* 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;
AsyncWebHeader *_headers;
String _contentType;
size_t _contentLength;
bool _sendContentLength;
bool _chunked;
2015-12-19 08:53:33 -08:00
size_t _headLength;
size_t _sentLength;
size_t _ackedLength;
WebResponseState _state;
const char* _responseCodeToString(int code);
public:
AsyncWebServerResponse();
virtual ~AsyncWebServerResponse();
virtual void setContentLength(size_t len);
virtual void setContentType(String type);
2015-12-19 08:53:33 -08:00
virtual void addHeader(String name, String value);
virtual String _assembleHead(uint8_t version);
virtual bool _started();
2015-12-19 08:53:33 -08:00
virtual bool _finished();
virtual bool _failed();
2016-04-08 07:43:16 -07:00
virtual bool _sourceValid();
2015-12-19 08:53:33 -08:00
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, 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;
class AsyncWebServer {
private:
AsyncServer _server;
AsyncWebRewrite* _rewrites;
2015-12-19 08:53:33 -08:00
AsyncWebHandler* _handlers;
AsyncWebHandler* _catchAllHandler;
public:
AsyncWebServer(uint16_t port);
~AsyncWebServer();
2015-12-19 08:53:33 -08:00
void begin();
AsyncWebRewrite& addRewrite(AsyncWebRewrite* rewrite);
AsyncWebRewrite& rewrite(const char* from, const char* to);
AsyncWebHandler& addHandler(AsyncWebHandler* handler);
AsyncCallbackWebHandler& on(const char* uri, ArRequestHandlerFunction onRequest);
AsyncCallbackWebHandler& on(const char* uri, WebRequestMethod method, ArRequestHandlerFunction onRequest);
AsyncCallbackWebHandler& on(const char* uri, WebRequestMethod method, ArRequestHandlerFunction onRequest, ArUploadHandlerFunction onUpload);
AsyncCallbackWebHandler& on(const char* uri, WebRequestMethod method, ArRequestHandlerFunction onRequest, ArUploadHandlerFunction onUpload, ArBodyHandlerFunction onBody);
2015-12-19 08:53:33 -08:00
AsyncStaticWebHandler& serveStatic(const char* uri, fs::FS& fs, const char* path, const char* cache_control = NULL);
2015-12-19 08:53:33 -08:00
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 _handleDisconnect(AsyncWebServerRequest *request);
void _attachHandler(AsyncWebServerRequest *request);
void _rewriteRequest(AsyncWebServerRequest *request);
2015-12-19 08:53:33 -08:00
};
#include "WebResponseImpl.h"
#include "WebHandlerImpl.h"
2016-04-23 05:11:32 -07:00
#include "AsyncWebSocket.h"
2015-12-19 08:53:33 -08:00
#endif /* _AsyncWebServer_H_ */