Rearrange and rename files and add index to chunked responses

This commit is contained in:
Me No Dev 2016-02-09 01:47:03 +02:00
parent 97c938803c
commit 40d5d4415e
10 changed files with 678 additions and 462 deletions

View File

@ -235,7 +235,7 @@ request->send("text/plain", 128, [](uint8_t *buffer, size_t maxLen) -> size_t {
### Respond with content using a callback and extra headers
```cpp
//send 128 bytes as plain text
AsyncWebServerResponse *response = request->beginResponse("text/plain", 128, [](uint8_t *buffer, size_t maxLen) -> size_t {
AsyncWebServerResponse *response = request->beginResponse("text/plain", 128, [](uint8_t *buffer, size_t maxLen, size_t index) -> size_t {
//Write up to "maxLen" bytes into "buffer" and return the amount written.
//You will not be asked for more bytes once the content length has been reached.
//Keep in mind that you can not delay or yield waiting for more data!
@ -249,7 +249,7 @@ request->send(response);
### Chunked Response
Used when content length is unknown. Works best if the client supports HTTP/1.1
```cpp
AsyncWebServerResponse *response = request->beginChunkedResponse("text/plain", [](uint8_t *buffer, size_t maxLen) -> size_t {
AsyncWebServerResponse *response = request->beginChunkedResponse("text/plain", [](uint8_t *buffer, size_t maxLen, size_t index) -> size_t {
//Write up to "maxLen" bytes into "buffer" and return the amount written.
//You will be asked for more data until 0 is returned
//Keep in mind that you can not delay or yield waiting for more data!
@ -309,6 +309,28 @@ response->print("</body></html>");
request->send(response);
```
### Send a large webpage from PROGMEM using chunked response
Example provided by [@nouser2013](https://github.com/nouser2013)
```cpp
const char indexhtml[] PROGMEM = "..."; // large char array, tested with 5k
AsyncWebServerResponse *response = request->beginResponse(
String("text/html"),
strlen_P(indexhtml),
[](uint8_t *buffer, size_t maxLen, size_t alreadySent) -> size_t {
if (strlen_P(indexhtml+sentCounter)>maxLen) {
// We have more to read than fits in maxLen Buffer
memcpy_P((char*)buffer, indexhtml+sentCounter, maxLen);
return maxLen;
}
// Ok, last chunk
memcpy_P((char*)buffer, indexhtml+sentCounter, strlen_P(indexhtml+sentCounter));
return strlen_P(indexhtml+sentCounter); // Return from here to end of indexhtml
}
);
response->addHeader("Server", "MyServerString");
request->send(response);
```
### ArduinoJson Basic Response
This way of sending Json is great for when the result is below 4KB
```cpp

View File

@ -1,3 +1,23 @@
/*
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_
@ -76,7 +96,7 @@ class AsyncWebHeader {
* REQUEST :: Each incoming Client is wrapped inside a Request and both live together until disconnect
* */
typedef std::function<size_t(uint8_t*, size_t)> AwsResponseFiller;
typedef std::function<size_t(uint8_t*, size_t, size_t)> AwsResponseFiller;
class AsyncWebServerRequest {
private:
@ -286,6 +306,6 @@ class AsyncWebServer {
void _handleRequest(AsyncWebServerRequest *request);
};
#include "AsyncWebServerResponseImpl.h"
#include <WebResponseImpl.h>
#endif /* _AsyncWebServer_H_ */

View File

@ -1,8 +1,22 @@
/*
* StringArray.h
*
* Created on: 18.12.2015 г.
* Author: ficeto
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 STRINGARRAY_H_

View File

@ -1,8 +1,22 @@
/*
* AsyncWebServerHandlerImpl.h
*
* Created on: 19.12.2015 г.
* Author: ficeto
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 ASYNCWEBSERVERHANDLERIMPL_H_
@ -10,18 +24,19 @@
#include "stddef.h"
#include "ESPAsyncWebServer.h"
class AsyncStaticWebHandler: public AsyncWebHandler {
private:
String _getPath(AsyncWebServerRequest *request);
protected:
FS _fs;
fs::FS _fs;
String _uri;
String _path;
String _cache_header;
bool _isFile;
public:
AsyncStaticWebHandler(FS& fs, const char* path, const char* uri, const char* cache_header)
AsyncStaticWebHandler(fs::FS& fs, const char* path, const char* uri, const char* cache_header)
: _fs(fs), _uri(uri), _path(path), _cache_header(cache_header){
_isFile = _fs.exists(path) || _fs.exists((String(path)+".gz").c_str());

View File

@ -1,11 +1,25 @@
/*
* WebHandlers.cpp
*
* Created on: 18.12.2015 г.
* Author: ficeto
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
*/
#include <WebHandlerImpl.h>
#include "ESPAsyncWebServer.h"
#include "AsyncWebServerHandlerImpl.h"
bool AsyncStaticWebHandler::canHandle(AsyncWebServerRequest *request)
{

409
src/WebRequest.cpp Normal file
View File

@ -0,0 +1,409 @@
/*
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
*/
#include "ESPAsyncWebServer.h"
#include <libb64/cencode.h>
#include <WebResponseImpl.h>
#ifndef ESP8266
#define os_strlen strlen
#endif
AsyncWebServerRequest::AsyncWebServerRequest(AsyncWebServer* s, AsyncClient* c)
: _client(c)
, _server(s)
, _handler(NULL)
, _response(NULL)
, _interestingHeaders(new StringArray())
, _temp()
, _parseState(0)
, _version(0)
, _method(HTTP_ANY)
, _url()
, _host()
, _contentType()
, _boundary()
, _authorization()
, _isMultipart(false)
, _isPlainPost(false)
, _expectingContinue(false)
, _contentLength(0)
, _parsedLength(0)
, _headers(NULL)
, _params(NULL)
, _multiParseState(0)
, _boundaryPosition(0)
, _itemStartIndex(0)
, _itemSize(0)
, _itemName()
, _itemFilename()
, _itemType()
, _itemValue()
, _itemBuffer(0)
, _itemBufferIndex(0)
, _itemIsFile(false)
, next(NULL)
{
c->onError([](void *r, AsyncClient* c, int8_t error){ AsyncWebServerRequest *req = (AsyncWebServerRequest*)r; req->_onError(error); }, this);
c->onAck([](void *r, AsyncClient* c, size_t len, uint32_t time){ AsyncWebServerRequest *req = (AsyncWebServerRequest*)r; req->_onAck(len, time); }, this);
c->onDisconnect([](void *r, AsyncClient* c){ AsyncWebServerRequest *req = (AsyncWebServerRequest*)r; req->_onDisconnect(); }, this);
c->onTimeout([](void *r, AsyncClient* c, uint32_t time){ AsyncWebServerRequest *req = (AsyncWebServerRequest*)r; req->_onTimeout(time); }, this);
c->onData([](void *r, AsyncClient* c, void *buf, size_t len){ AsyncWebServerRequest *req = (AsyncWebServerRequest*)r; req->_onData(buf, len); }, this);
c->onPoll([](void *r, AsyncClient* c){ AsyncWebServerRequest *req = (AsyncWebServerRequest*)r; req->_onPoll(); }, this);
}
AsyncWebServerRequest::~AsyncWebServerRequest(){
while(_headers != NULL){
AsyncWebHeader *h = _headers;
_headers = h->next;
delete h;
}
while(_params != NULL){
AsyncWebParameter *p = _params;
_params = p->next;
delete p;
}
_interestingHeaders->free();
delete _interestingHeaders;
if(_response != NULL){
delete _response;
}
}
void AsyncWebServerRequest::_onPoll(){
//os_printf("p\n");
if(_response != NULL && !_response->_finished() && _client->canSend()){
_response->_ack(this, 0, 0);
}
}
void AsyncWebServerRequest::_onAck(size_t len, uint32_t time){
//os_printf("a:%u:%u\n", len, time);
if(_response != NULL){
if(!_response->_finished()){
_response->_ack(this, len, time);
} else {
AsyncWebServerResponse* r = _response;
_response = NULL;
delete r;
}
}
}
void AsyncWebServerRequest::_onError(int8_t error){
if(error != -11)
os_printf("ERROR[%d] %s, state: %s\n", error, _client->errorToString(error), _client->stateToString());
}
void AsyncWebServerRequest::_onTimeout(uint32_t time){
os_printf("TIMEOUT: %u, state: %s\n", time, _client->stateToString());
_client->close();
}
void AsyncWebServerRequest::_onDisconnect(){
//os_printf("d\n");
_client->free();
delete _client;
_server->_handleDisconnect(this);
}
void AsyncWebServerRequest::_addParam(AsyncWebParameter *p){
if(_params == NULL)
_params = p;
else {
AsyncWebParameter *ps = _params;
while(ps->next != NULL) ps = ps->next;
ps->next = p;
}
}
int AsyncWebServerRequest::headers(){
int i = 0;
AsyncWebHeader* h = _headers;
while(h != NULL){
i++; h = h->next;
}
return i;
}
bool AsyncWebServerRequest::hasHeader(String name){
AsyncWebHeader* h = _headers;
while(h != NULL){
if(h->name() == name)
return true;
h = h->next;
}
return false;
}
AsyncWebHeader* AsyncWebServerRequest::getHeader(String name){
AsyncWebHeader* h = _headers;
while(h != NULL){
if(h->name() == name)
return h;
h = h->next;
}
return NULL;
}
AsyncWebHeader* AsyncWebServerRequest::getHeader(int num){
int i = 0;
AsyncWebHeader* h = _headers;
while(h != NULL){
if(num == i++)
return h;
h = h->next;
}
return NULL;
}
int AsyncWebServerRequest::params(){
int i = 0;
AsyncWebParameter* h = _params;
while(h != NULL){
i++; h = h->next;
}
return i;
}
bool AsyncWebServerRequest::hasParam(String name, bool post, bool file){
AsyncWebParameter* h = _params;
while(h != NULL){
if(h->name() == name && h->isPost() == post && h->isFile() == file)
return true;
h = h->next;
}
return false;
}
AsyncWebParameter* AsyncWebServerRequest::getParam(String name, bool post, bool file){
AsyncWebParameter* h = _params;
while(h != NULL){
if(h->name() == name && h->isPost() == post && h->isFile() == file)
return h;
h = h->next;
}
return NULL;
}
AsyncWebParameter* AsyncWebServerRequest::getParam(int num){
int i = 0;
AsyncWebParameter* h = _params;
while(h != NULL){
if(num == i++)
return h;
h = h->next;
}
return NULL;
}
void AsyncWebServerRequest::addInterestingHeader(String name){
if(!_interestingHeaders->contains(name)) _interestingHeaders->add(name);
}
void AsyncWebServerRequest::send(AsyncWebServerResponse *response){
_response = response;
_response->_respond(this);
}
AsyncWebServerResponse * AsyncWebServerRequest::beginResponse(int code, String contentType, String content){
return new AsyncBasicResponse(code, contentType, content);
}
AsyncWebServerResponse * AsyncWebServerRequest::beginResponse(FS &fs, String path, String contentType, bool download){
if(fs.exists(path) || (!download && fs.exists(path+".gz")))
return new AsyncFileResponse(fs, path, contentType, download);
return NULL;
}
AsyncWebServerResponse * AsyncWebServerRequest::beginResponse(Stream &stream, String contentType, size_t len){
return new AsyncStreamResponse(stream, contentType, len);
}
AsyncWebServerResponse * AsyncWebServerRequest::beginResponse(String contentType, size_t len, AwsResponseFiller callback){
return new AsyncCallbackResponse(contentType, len, callback);
}
AsyncWebServerResponse * AsyncWebServerRequest::beginChunkedResponse(String contentType, AwsResponseFiller callback){
if(_version)
return new AsyncChunkedResponse(contentType, callback);
return new AsyncCallbackResponse(contentType, 0, callback);
}
AsyncResponseStream * AsyncWebServerRequest::beginResponseStream(String contentType, size_t bufferSize){
return new AsyncResponseStream(contentType, bufferSize);
}
void AsyncWebServerRequest::send(int code, String contentType, String content){
send(beginResponse(code, contentType, content));
}
void AsyncWebServerRequest::send(FS &fs, String path, String contentType, bool download){
if(fs.exists(path) || (!download && fs.exists(path+".gz"))){
send(beginResponse(fs, path, contentType, download));
} else send(404);
}
void AsyncWebServerRequest::send(Stream &stream, String contentType, size_t len){
send(beginResponse(stream, contentType, len));
}
void AsyncWebServerRequest::send(String contentType, size_t len, AwsResponseFiller callback){
send(beginResponse(contentType, len, callback));
}
void AsyncWebServerRequest::sendChunked(String contentType, AwsResponseFiller callback){
send(beginChunkedResponse(contentType, callback));
}
bool AsyncWebServerRequest::authenticate(const char * username, const char * password){
if(_authorization.length()){
char toencodeLen = os_strlen(username)+os_strlen(password)+1;
char *toencode = new char[toencodeLen];
if(toencode == NULL){
return false;
}
char *encoded = new char[base64_encode_expected_len(toencodeLen)+1];
if(encoded == NULL){
delete[] toencode;
return false;
}
sprintf(toencode, "%s:%s", username, password);
if(base64_encode_chars(toencode, toencodeLen, encoded) > 0 && _authorization.equals(encoded)){
delete[] toencode;
delete[] encoded;
return true;
}
delete[] toencode;
delete[] encoded;
}
return false;
}
bool AsyncWebServerRequest::authenticate(const char * hash){
return (_authorization.length() && (_authorization == String(hash)));
}
void AsyncWebServerRequest::requestAuthentication(){
AsyncWebServerResponse * r = beginResponse(401);
r->addHeader("WWW-Authenticate", "Basic realm=\"Login Required\"");
send(r);
}
bool AsyncWebServerRequest::hasArg(const char* name){
AsyncWebParameter* h = _params;
while(h != NULL){
if(h->name() == String(name))
return true;
h = h->next;
}
return false;
}
String AsyncWebServerRequest::arg(const char* name){
AsyncWebParameter* h = _params;
while(h != NULL){
if(h->name() == String(name))
return h->value();
h = h->next;
}
return String();
}
String AsyncWebServerRequest::arg(int i){
return getParam(i)->value();
}
String AsyncWebServerRequest::argName(int i){
return getParam(i)->name();
}
String AsyncWebServerRequest::header(const char* name){
AsyncWebHeader* h = getHeader(String(name));
if(h)
return h->value();
return String();
}
String AsyncWebServerRequest::header(int i){
AsyncWebHeader* h = getHeader(i);
if(h)
return h->value();
return String();
}
String AsyncWebServerRequest::headerName(int i){
AsyncWebHeader* h = getHeader(i);
if(h)
return h->name();
return String();
}
bool AsyncWebServerRequest::hasHeader(const char* name){
return hasHeader(String(name));
}
String AsyncWebServerRequest::urlDecode(const String& text){
String decoded = "";
char temp[] = "0x00";
unsigned int len = text.length();
unsigned int i = 0;
while (i < len){
char decodedChar;
char encodedChar = text.charAt(i++);
if ((encodedChar == '%') && (i + 1 < len)){
temp[2] = text.charAt(i++);
temp[3] = text.charAt(i++);
decodedChar = strtol(temp, NULL, 16);
} else {
if (encodedChar == '+'){
decodedChar = ' ';
} else {
decodedChar = encodedChar; // normal ascii char
}
}
decoded += decodedChar;
}
return decoded;
}
const char * AsyncWebServerRequest::methodToString(){
if(_method == HTTP_ANY) return "ANY";
else if(_method == HTTP_GET) return "GET";
else if(_method == HTTP_POST) return "POST";
else if(_method == HTTP_DELETE) return "DELETE";
else if(_method == HTTP_PUT) return "PUT";
else if(_method == HTTP_PATCH) return "PATCH";
else if(_method == HTTP_HEAD) return "HEAD";
else if(_method == HTTP_OPTIONS) return "OPTIONS";
return "UNKNOWN";
}

View File

@ -1,104 +1,95 @@
/*
* WebServerClient.cpp
*
* Created on: 18.12.2015 г.
* Author: ficeto
*/
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
*/
#include <WebResponseImpl.h>
#include "ESPAsyncWebServer.h"
#include "AsyncWebServerResponseImpl.h"
#include <libb64/cencode.h>
#ifndef ESP8266
#define os_strlen strlen
#endif
#define __is_param_char(c) ((c) && ((c) != '{') && ((c) != '[') && ((c) != '&') && ((c) != '='))
enum { PARSE_REQ_START, PARSE_REQ_HEADERS, PARSE_REQ_BODY, PARSE_REQ_END, PARSE_REQ_FAIL };
AsyncWebServerRequest::AsyncWebServerRequest(AsyncWebServer* s, AsyncClient* c)
: _client(c)
, _server(s)
, _handler(NULL)
, _response(NULL)
, _interestingHeaders(new StringArray())
, _temp()
, _parseState(0)
, _version(0)
, _method(HTTP_ANY)
, _url()
, _host()
, _contentType()
, _boundary()
, _authorization()
, _isMultipart(false)
, _isPlainPost(false)
, _expectingContinue(false)
, _contentLength(0)
, _parsedLength(0)
, _headers(NULL)
, _params(NULL)
, _multiParseState(0)
, _boundaryPosition(0)
, _itemStartIndex(0)
, _itemSize(0)
, _itemName()
, _itemFilename()
, _itemType()
, _itemValue()
, _itemBuffer(0)
, _itemBufferIndex(0)
, _itemIsFile(false)
, next(NULL)
{
c->onError([](void *r, AsyncClient* c, int8_t error){ AsyncWebServerRequest *req = (AsyncWebServerRequest*)r; req->_onError(error); }, this);
c->onAck([](void *r, AsyncClient* c, size_t len, uint32_t time){ AsyncWebServerRequest *req = (AsyncWebServerRequest*)r; req->_onAck(len, time); }, this);
c->onDisconnect([](void *r, AsyncClient* c){ AsyncWebServerRequest *req = (AsyncWebServerRequest*)r; req->_onDisconnect(); }, this);
c->onTimeout([](void *r, AsyncClient* c, uint32_t time){ AsyncWebServerRequest *req = (AsyncWebServerRequest*)r; req->_onTimeout(time); }, this);
c->onData([](void *r, AsyncClient* c, void *buf, size_t len){ AsyncWebServerRequest *req = (AsyncWebServerRequest*)r; req->_onData(buf, len); }, this);
c->onPoll([](void *r, AsyncClient* c){ AsyncWebServerRequest *req = (AsyncWebServerRequest*)r; req->_onPoll(); }, this);
void AsyncWebServerRequest::_parseByte(uint8_t data){
if((char)data != '\r' && (char)data != '\n')
_temp += (char)data;
if((char)data == '\n')
_parseLine();
}
AsyncWebServerRequest::~AsyncWebServerRequest(){
while(_headers != NULL){
AsyncWebHeader *h = _headers;
_headers = h->next;
delete h;
void AsyncWebServerRequest::_parseLine(){
if(_parseState == PARSE_REQ_START){
if(_temp.length()){
_parseReqHead();//head!
_parseState = PARSE_REQ_HEADERS;
} else {
_parseState = PARSE_REQ_FAIL;
_client->close();
}
return;
}
while(_params != NULL){
AsyncWebParameter *p = _params;
_params = p->next;
delete p;
if(_parseState == PARSE_REQ_HEADERS){
if(!_temp.length()){
_parseReqHeader();//header!
} else {
//end of headers
if(_expectingContinue){
const char * response = "HTTP/1.1 100 Continue\r\n\r\n";
_client->write(response, os_strlen(response));
}
if(_contentLength){
_parseState = PARSE_REQ_BODY;
} else {
_parseState = PARSE_REQ_END;
if(_handler) _handler->handleRequest(this);
else send(501);
}
}
_interestingHeaders->free();
delete _interestingHeaders;
if(_response != NULL){
delete _response;
}
}
void AsyncWebServerRequest::_onData(void *buf, size_t len){
if(_parseState < PARSE_REQ_BODY){
//ToDo: make it parse the whole packet at once
size_t i;
for(i=0; i<len; i++){
if(_parseState < PARSE_REQ_BODY)
_parseByte(((uint8_t*)buf)[i]);
_parseByte(((uint8_t*)buf)[i]);//parse byte for head/header
else
return _onData((void *)((uint8_t*)buf+i), len-i);
return _onData((void *)((uint8_t*)buf+i), len-i);//the last byte switched the mode so forward
}
} else if(_parseState == PARSE_REQ_BODY){
if(_isMultipart){
size_t i;
for(i=0; i<len; i++){
_parseMultipartPostByte(((uint8_t*)buf)[i], i == len - 1);
_parseMultipartPostByte(((uint8_t*)buf)[i], i == len - 1);//parse multipart post byte
_parsedLength++;
}
} else {
//ToDo: make it parse the whole packet at once
if(_parsedLength == 0){
if(_contentType.startsWith("application/x-www-form-urlencoded")){
_isPlainPost = true;
@ -114,11 +105,13 @@ void AsyncWebServerRequest::_onData(void *buf, size_t len){
if(_handler) _handler->handleBody(this, (uint8_t*)buf, len, _parsedLength, _contentLength);
_parsedLength += len;
} else {
//ToDo: make it parse the whole packet at once
size_t i;
for(i=0; i<len; i++){
_parsedLength++;
_parsePlainPostChar(((uint8_t*)buf)[i]);
_parsePlainPostChar(((uint8_t*)buf)[i]);//parse plain post byte
}
}
}
@ -131,52 +124,9 @@ void AsyncWebServerRequest::_onData(void *buf, size_t len){
}
}
void AsyncWebServerRequest::_onPoll(){
//os_printf("p\n");
if(_response != NULL && !_response->_finished() && _client->canSend()){
_response->_ack(this, 0, 0);
}
}
void AsyncWebServerRequest::_onAck(size_t len, uint32_t time){
//os_printf("a:%u:%u\n", len, time);
if(_response != NULL){
if(!_response->_finished()){
_response->_ack(this, len, time);
} else {
AsyncWebServerResponse* r = _response;
_response = NULL;
delete r;
}
}
}
void AsyncWebServerRequest::_onError(int8_t error){
if(error != -11)
os_printf("ERROR[%d] %s, state: %s\n", error, _client->errorToString(error), _client->stateToString());
}
void AsyncWebServerRequest::_onTimeout(uint32_t time){
os_printf("TIMEOUT: %u, state: %s\n", time, _client->stateToString());
_client->close();
}
void AsyncWebServerRequest::_onDisconnect(){
//os_printf("d\n");
_client->free();
delete _client;
_server->_handleDisconnect(this);
}
void AsyncWebServerRequest::_addParam(AsyncWebParameter *p){
if(_params == NULL)
_params = p;
else {
AsyncWebParameter *ps = _params;
while(ps->next != NULL) ps = ps->next;
ps->next = p;
}
}
//
// REQUEST HEAD
//
void AsyncWebServerRequest::_addGetParam(String param){
param = urlDecode(param);
@ -189,8 +139,8 @@ void AsyncWebServerRequest::_addGetParam(String param){
_addParam(new AsyncWebParameter(name, value));
}
bool AsyncWebServerRequest::_parseReqHead(){
//Method
String m = _temp.substring(0, _temp.indexOf(' '));
if(m == "GET"){
_method = HTTP_GET;
@ -208,6 +158,7 @@ bool AsyncWebServerRequest::_parseReqHead(){
_method = HTTP_OPTIONS;
}
//URL
_temp = _temp.substring(_temp.indexOf(' ')+1);
String u = _temp.substring(0, _temp.indexOf(' '));
String g = String();
@ -216,20 +167,23 @@ bool AsyncWebServerRequest::_parseReqHead(){
u = u.substring(0, u.indexOf('?'));
}
_url = u;
//Parameters
if(g.length()){
while(true){
if(g.length() == 0)
break;
if(g.indexOf('&') > 0){
_addGetParam(g.substring(0, g.indexOf('&')));
_addGetParam(g.substring(0, g.indexOf('&')));//GET Param
g = g.substring(g.indexOf('&') + 1);
} else {
_addGetParam(g);
_addGetParam(g);//Get Param
break;
}
}
}
//Version
_temp = _temp.substring(_temp.indexOf(' ')+1);
if(_temp.startsWith("HTTP/1.1"))
_version = 1;
@ -237,6 +191,10 @@ bool AsyncWebServerRequest::_parseReqHead(){
return true;
}
//
// HEADERS
//
bool AsyncWebServerRequest::_parseReqHeader(){
if(_temp.indexOf(':')){
AsyncWebHeader *h = new AsyncWebHeader(_temp);
@ -282,6 +240,10 @@ bool AsyncWebServerRequest::_parseReqHeader(){
return true;
}
//
// PLAIN POST
//
void AsyncWebServerRequest::_parsePlainPostChar(uint8_t data){
if(data && (char)data != '&')
_temp += (char)data;
@ -298,14 +260,9 @@ void AsyncWebServerRequest::_parsePlainPostChar(uint8_t data){
}
}
void AsyncWebServerRequest::_handleUploadByte(uint8_t data, bool last){
_itemBuffer[_itemBufferIndex++] = data;
if(last){
if(_handler)
_handler->handleUpload(this, _itemFilename, _itemSize - _itemBufferIndex, _itemBuffer, _itemBufferIndex, false);
_itemBufferIndex = 0;
}
}
//
// MULTIPART POST
//
enum {
EXPECT_BOUNDARY,
@ -321,6 +278,15 @@ enum {
PARSE_ERROR
};
void AsyncWebServerRequest::_handleUploadByte(uint8_t data, bool last){
_itemBuffer[_itemBufferIndex++] = data;
if(last){
if(_handler)
_handler->handleUpload(this, _itemFilename, _itemSize - _itemBufferIndex, _itemBuffer, _itemBufferIndex, false);
_itemBufferIndex = 0;
}
}
void AsyncWebServerRequest::_parseMultipartPostByte(uint8_t data, bool last){
#define itemWriteByte(b) do { _itemSize++; if(_itemIsFile) _handleUploadByte(b, last); else _itemValue+=(char)(b); } while(0)
@ -475,310 +441,7 @@ void AsyncWebServerRequest::_parseMultipartPostByte(uint8_t data, bool last){
}
}
void AsyncWebServerRequest::_parseLine(){
if(_parseState == PARSE_REQ_START){
if(!_temp.length()){
_parseState = PARSE_REQ_FAIL;
_client->close();
} else {
_parseReqHead();
_parseState = PARSE_REQ_HEADERS;
}
return;
}
if(_parseState == PARSE_REQ_HEADERS){
if(!_temp.length()){
//end of headers
if(_expectingContinue){
const char * response = "HTTP/1.1 100 Continue\r\n\r\n";
_client->write(response, os_strlen(response));
}
if(_contentLength){
_parseState = PARSE_REQ_BODY;
} else {
_parseState = PARSE_REQ_END;
if(_handler) _handler->handleRequest(this);
else send(501);
}
} else _parseReqHeader();
}
}
void AsyncWebServerRequest::_parseByte(uint8_t data){
if((char)data != '\r' && (char)data != '\n')
_temp += (char)data;
if((char)data == '\n')
_parseLine();
}
int AsyncWebServerRequest::headers(){
int i = 0;
AsyncWebHeader* h = _headers;
while(h != NULL){
i++; h = h->next;
}
return i;
}
bool AsyncWebServerRequest::hasHeader(String name){
AsyncWebHeader* h = _headers;
while(h != NULL){
if(h->name() == name)
return true;
h = h->next;
}
return false;
}
AsyncWebHeader* AsyncWebServerRequest::getHeader(String name){
AsyncWebHeader* h = _headers;
while(h != NULL){
if(h->name() == name)
return h;
h = h->next;
}
return NULL;
}
AsyncWebHeader* AsyncWebServerRequest::getHeader(int num){
int i = 0;
AsyncWebHeader* h = _headers;
while(h != NULL){
if(num == i++)
return h;
h = h->next;
}
return NULL;
}
int AsyncWebServerRequest::params(){
int i = 0;
AsyncWebParameter* h = _params;
while(h != NULL){
i++; h = h->next;
}
return i;
}
bool AsyncWebServerRequest::hasParam(String name, bool post, bool file){
AsyncWebParameter* h = _params;
while(h != NULL){
if(h->name() == name && h->isPost() == post && h->isFile() == file)
return true;
h = h->next;
}
return false;
}
AsyncWebParameter* AsyncWebServerRequest::getParam(String name, bool post, bool file){
AsyncWebParameter* h = _params;
while(h != NULL){
if(h->name() == name && h->isPost() == post && h->isFile() == file)
return h;
h = h->next;
}
return NULL;
}
AsyncWebParameter* AsyncWebServerRequest::getParam(int num){
int i = 0;
AsyncWebParameter* h = _params;
while(h != NULL){
if(num == i++)
return h;
h = h->next;
}
return NULL;
}
void AsyncWebServerRequest::addInterestingHeader(String name){
if(!_interestingHeaders->contains(name)) _interestingHeaders->add(name);
}
void AsyncWebServerRequest::send(AsyncWebServerResponse *response){
_response = response;
_response->_respond(this);
}
AsyncWebServerResponse * AsyncWebServerRequest::beginResponse(int code, String contentType, String content){
return new AsyncBasicResponse(code, contentType, content);
}
AsyncWebServerResponse * AsyncWebServerRequest::beginResponse(FS &fs, String path, String contentType, bool download){
if(fs.exists(path) || (!download && fs.exists(path+".gz")))
return new AsyncFileResponse(fs, path, contentType, download);
return NULL;
}
AsyncWebServerResponse * AsyncWebServerRequest::beginResponse(Stream &stream, String contentType, size_t len){
return new AsyncStreamResponse(stream, contentType, len);
}
AsyncWebServerResponse * AsyncWebServerRequest::beginResponse(String contentType, size_t len, AwsResponseFiller callback){
return new AsyncCallbackResponse(contentType, len, callback);
}
AsyncWebServerResponse * AsyncWebServerRequest::beginChunkedResponse(String contentType, AwsResponseFiller callback){
if(_version)
return new AsyncChunkedResponse(contentType, callback);
return new AsyncCallbackResponse(contentType, 0, callback);
}
AsyncResponseStream * AsyncWebServerRequest::beginResponseStream(String contentType, size_t bufferSize){
return new AsyncResponseStream(contentType, bufferSize);
}
void AsyncWebServerRequest::send(int code, String contentType, String content){
send(beginResponse(code, contentType, content));
}
void AsyncWebServerRequest::send(FS &fs, String path, String contentType, bool download){
if(fs.exists(path) || (!download && fs.exists(path+".gz"))){
send(beginResponse(fs, path, contentType, download));
} else send(404);
}
void AsyncWebServerRequest::send(Stream &stream, String contentType, size_t len){
send(beginResponse(stream, contentType, len));
}
void AsyncWebServerRequest::send(String contentType, size_t len, AwsResponseFiller callback){
send(beginResponse(contentType, len, callback));
}
void AsyncWebServerRequest::sendChunked(String contentType, AwsResponseFiller callback){
send(beginChunkedResponse(contentType, callback));
}
bool AsyncWebServerRequest::authenticate(const char * username, const char * password){
if(_authorization.length()){
char toencodeLen = os_strlen(username)+os_strlen(password)+1;
char *toencode = new char[toencodeLen];
if(toencode == NULL){
return false;
}
char *encoded = new char[base64_encode_expected_len(toencodeLen)+1];
if(encoded == NULL){
delete[] toencode;
return false;
}
sprintf(toencode, "%s:%s", username, password);
if(base64_encode_chars(toencode, toencodeLen, encoded) > 0 && _authorization.equals(encoded)){
delete[] toencode;
delete[] encoded;
return true;
}
delete[] toencode;
delete[] encoded;
}
return false;
}
bool AsyncWebServerRequest::authenticate(const char * hash){
return (_authorization.length() && (_authorization == String(hash)));
}
void AsyncWebServerRequest::requestAuthentication(){
AsyncWebServerResponse * r = beginResponse(401);
r->addHeader("WWW-Authenticate", "Basic realm=\"Login Required\"");
send(r);
}
bool AsyncWebServerRequest::hasArg(const char* name){
AsyncWebParameter* h = _params;
while(h != NULL){
if(h->name() == String(name))
return true;
h = h->next;
}
return false;
}
String AsyncWebServerRequest::arg(const char* name){
AsyncWebParameter* h = _params;
while(h != NULL){
if(h->name() == String(name))
return h->value();
h = h->next;
}
return String();
}
String AsyncWebServerRequest::arg(int i){
return getParam(i)->value();
}
String AsyncWebServerRequest::argName(int i){
return getParam(i)->name();
}
String AsyncWebServerRequest::header(const char* name){
AsyncWebHeader* h = getHeader(String(name));
if(h)
return h->value();
return String();
}
String AsyncWebServerRequest::header(int i){
AsyncWebHeader* h = getHeader(i);
if(h)
return h->value();
return String();
}
String AsyncWebServerRequest::headerName(int i){
AsyncWebHeader* h = getHeader(i);
if(h)
return h->name();
return String();
}
bool AsyncWebServerRequest::hasHeader(const char* name){
return hasHeader(String(name));
}
String AsyncWebServerRequest::urlDecode(const String& text){
String decoded = "";
char temp[] = "0x00";
unsigned int len = text.length();
unsigned int i = 0;
while (i < len){
char decodedChar;
char encodedChar = text.charAt(i++);
if ((encodedChar == '%') && (i + 1 < len)){
temp[2] = text.charAt(i++);
temp[3] = text.charAt(i++);
decodedChar = strtol(temp, NULL, 16);
} else {
if (encodedChar == '+'){
decodedChar = ' ';
} else {
decodedChar = encodedChar; // normal ascii char
}
}
decoded += decodedChar;
}
return decoded;
}
const char * AsyncWebServerRequest::methodToString(){
if(_method == HTTP_ANY) return "ANY";
else if(_method == HTTP_GET) return "GET";
else if(_method == HTTP_POST) return "POST";
else if(_method == HTTP_DELETE) return "DELETE";
else if(_method == HTTP_PUT) return "PUT";
else if(_method == HTTP_PATCH) return "PATCH";
else if(_method == HTTP_HEAD) return "HEAD";
else if(_method == HTTP_OPTIONS) return "OPTIONS";
return "UNKNOWN";
}

View File

@ -1,13 +1,29 @@
/*
* AsyncWebImpl.h
*
* Created on: 19.12.2015 г.
* Author: ficeto
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 ASYNCWEBSERVERRESPONSEIMPL_H_
#define ASYNCWEBSERVERRESPONSEIMPL_H_
#include "ESPAsyncWebServer.h"
class AsyncBasicResponse: public AsyncWebServerResponse {
private:
String _content;

View File

@ -1,5 +1,25 @@
/*
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
*/
#include <WebResponseImpl.h>
#include "ESPAsyncWebServer.h"
#include "AsyncWebServerResponseImpl.h"
#include "cbuf.h"
/*
@ -265,6 +285,9 @@ size_t AsyncAbstractResponse::_ack(AsyncWebServerRequest *request, size_t len, u
if(outLen)
outLen = request->client()->write((const char*)buf, outLen);
if(_chunked)
_sentLength += readLen;
else
_sentLength += outLen;
free(buf);
@ -290,7 +313,7 @@ size_t AsyncAbstractResponse::_ack(AsyncWebServerRequest *request, size_t len, u
if(!_sendContentLength || _ackedLength >= (_headLength+_contentLength)){
_state = RESPONSE_END;
if(!_chunked && !_sendContentLength)
request->client()->close(true);
request->client()->close(false);
}
}
return 0;
@ -381,7 +404,7 @@ AsyncCallbackResponse::AsyncCallbackResponse(String contentType, size_t len, Aws
}
size_t AsyncCallbackResponse::_fillBuffer(uint8_t *data, size_t len){
return _content(data, len);
return _content(data, len, _sentLength);
}
/*
@ -398,7 +421,7 @@ AsyncChunkedResponse::AsyncChunkedResponse(String contentType, AwsResponseFiller
}
size_t AsyncChunkedResponse::_fillBuffer(uint8_t *data, size_t len){
return _content(data, len);
return _content(data, len, _sentLength);
}

View File

@ -1,5 +1,25 @@
/*
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
*/
#include <WebHandlerImpl.h>
#include "ESPAsyncWebServer.h"
#include "AsyncWebServerHandlerImpl.h"
AsyncWebServer::AsyncWebServer(uint16_t port):_server(port), _handlers(0), _catchAllHandler(new AsyncCallbackWebHandler()){