2015-12-19 08:53:33 -08:00
/*
2016-02-08 16:56:01 -08:00
Asynchronous WebServer library for Espressif MCUs
2016-02-08 16:32:14 -08:00
2016-02-08 16:56:01 -08:00
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 08:53:33 -08:00
# include "ESPAsyncWebServer.h"
2016-02-08 16:56:01 -08:00
# include "WebResponseImpl.h"
2016-06-29 06:20:03 -07:00
# include "WebAuthentication.h"
2015-12-19 08:53:33 -08:00
2016-01-22 08:09:05 -08:00
# ifndef ESP8266
# define os_strlen strlen
# endif
2016-11-27 07:42:09 -08:00
static const String SharedEmptyString = String ( ) ;
2015-12-22 02:42:07 -08:00
# define __is_param_char(c) ((c) && ((c) != '{') && ((c) != '[') && ((c) != '&') && ((c) != '='))
2015-12-19 08:53:33 -08:00
enum { PARSE_REQ_START , PARSE_REQ_HEADERS , PARSE_REQ_BODY , PARSE_REQ_END , PARSE_REQ_FAIL } ;
2016-02-08 16:32:14 -08:00
AsyncWebServerRequest : : AsyncWebServerRequest ( AsyncWebServer * s , AsyncClient * c )
: _client ( c )
, _server ( s )
, _handler ( NULL )
, _response ( NULL )
, _temp ( )
, _parseState ( 0 )
, _version ( 0 )
, _method ( HTTP_ANY )
, _url ( )
, _host ( )
, _contentType ( )
, _boundary ( )
, _authorization ( )
2016-06-29 06:20:03 -07:00
, _isDigest ( false )
2016-02-08 16:32:14 -08:00
, _isMultipart ( false )
, _isPlainPost ( false )
, _expectingContinue ( false )
, _contentLength ( 0 )
, _parsedLength ( 0 )
2016-11-27 07:42:09 -08:00
, _headers ( LinkedList < AsyncWebHeader * > ( [ ] ( AsyncWebHeader * h ) { delete h ; } ) )
, _params ( LinkedList < AsyncWebParameter * > ( [ ] ( AsyncWebParameter * p ) { delete p ; } ) )
2016-02-08 16:32:14 -08:00
, _multiParseState ( 0 )
, _boundaryPosition ( 0 )
, _itemStartIndex ( 0 )
, _itemSize ( 0 )
, _itemName ( )
, _itemFilename ( )
, _itemType ( )
, _itemValue ( )
, _itemBuffer ( 0 )
, _itemBufferIndex ( 0 )
, _itemIsFile ( false )
2016-06-16 13:24:09 -07:00
, _tempObject ( NULL )
2016-02-08 16:32:14 -08:00
{
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 ) ;
2016-07-13 14:01:13 -07:00
c - > onDisconnect ( [ ] ( void * r , AsyncClient * c ) { AsyncWebServerRequest * req = ( AsyncWebServerRequest * ) r ; req - > _onDisconnect ( ) ; delete c ; } , this ) ;
2016-02-08 16:32:14 -08:00
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 ) ;
2015-12-19 08:53:33 -08:00
}
2016-02-08 16:32:14 -08:00
AsyncWebServerRequest : : ~ AsyncWebServerRequest ( ) {
2016-11-27 07:42:09 -08:00
_headers . free ( ) ;
2015-12-19 08:53:33 -08:00
2016-11-27 07:42:09 -08:00
_params . free ( ) ;
2016-02-08 16:32:14 -08:00
2016-11-27 07:42:09 -08:00
_interestingHeaders . free ( ) ;
2016-02-08 16:32:14 -08:00
if ( _response ! = NULL ) {
delete _response ;
}
2016-06-16 13:27:01 -07:00
if ( _tempObject ! = NULL ) {
2016-06-16 15:53:21 -07:00
free ( _tempObject ) ;
2016-06-16 13:09:58 -07:00
}
2016-09-23 03:48:35 -07:00
if ( _tempFile ) {
_tempFile . close ( ) ;
}
2015-12-19 08:53:33 -08:00
}
void AsyncWebServerRequest : : _onData ( void * buf , size_t len ) {
2017-01-22 02:47:21 -08:00
while ( true ) {
2015-12-19 08:53:33 -08:00
if ( _parseState < PARSE_REQ_BODY ) {
2016-06-17 07:42:47 -07:00
// Find new line in buf
char * str = ( char * ) buf ;
size_t i = 0 ;
for ( ; i < len ; i + + ) if ( str [ i ] = = ' \n ' ) break ;
if ( i = = len ) { // No new line, just add the buffer in _temp
char ch = str [ len - 1 ] ;
str [ len - 1 ] = 0 ;
_temp . reserve ( _temp . length ( ) + len ) ;
_temp . concat ( str ) ;
_temp . concat ( ch ) ;
} else { // Found new line - extract it and parse
str [ i ] = 0 ; // Terminate the string at the end of the line.
_temp . concat ( str ) ;
_temp . trim ( ) ;
_parseLine ( ) ;
2017-01-22 02:47:21 -08:00
if ( + + i < len ) {
// Still have more buffer to process
buf = str + i ;
len - = i ;
continue ;
}
2015-12-19 08:53:33 -08:00
}
} else if ( _parseState = = PARSE_REQ_BODY ) {
if ( _isMultipart ) {
size_t i ;
for ( i = 0 ; i < len ; i + + ) {
2016-02-08 16:32:14 -08:00
_parseMultipartPostByte ( ( ( uint8_t * ) buf ) [ i ] , i = = len - 1 ) ;
2015-12-19 08:53:33 -08:00
_parsedLength + + ;
}
} else {
if ( _parsedLength = = 0 ) {
2016-01-21 08:41:48 -08:00
if ( _contentType . startsWith ( " application/x-www-form-urlencoded " ) ) {
2015-12-19 08:53:33 -08:00
_isPlainPost = true ;
} else if ( _contentType = = " text/plain " & & __is_param_char ( ( ( char * ) buf ) [ 0 ] ) ) {
size_t i = 0 ;
while ( i < len & & __is_param_char ( ( ( char * ) buf ) [ i + + ] ) ) ;
if ( i < len & & ( ( char * ) buf ) [ i - 1 ] = = ' = ' ) {
_isPlainPost = true ;
}
}
}
if ( ! _isPlainPost ) {
2016-06-29 06:20:03 -07:00
//check if authenticated before calling the body
2015-12-19 08:53:33 -08:00
if ( _handler ) _handler - > handleBody ( this , ( uint8_t * ) buf , len , _parsedLength , _contentLength ) ;
_parsedLength + = len ;
} else {
size_t i ;
for ( i = 0 ; i < len ; i + + ) {
_parsedLength + + ;
2016-02-08 16:32:14 -08:00
_parsePlainPostChar ( ( ( uint8_t * ) buf ) [ i ] ) ;
2015-12-19 08:53:33 -08:00
}
}
}
if ( _parsedLength = = _contentLength ) {
_parseState = PARSE_REQ_END ;
2016-06-29 06:20:03 -07:00
//check if authenticated before calling handleRequest and request auth instead
2015-12-19 08:53:33 -08:00
if ( _handler ) _handler - > handleRequest ( this ) ;
else send ( 501 ) ;
}
}
2017-01-22 02:47:21 -08:00
break ;
}
2015-12-19 08:53:33 -08:00
}
2016-02-08 16:32:14 -08:00
void AsyncWebServerRequest : : _onPoll ( ) {
//os_printf("p\n");
2016-04-05 01:22:20 -07:00
if ( _response ! = NULL & & _client ! = NULL & & _client - > canSend ( ) & & ! _response - > _finished ( ) ) {
2016-02-08 16:32:14 -08:00
_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 ) {
2016-04-05 01:22:20 -07:00
2016-02-08 16:32:14 -08:00
}
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");
_server - > _handleDisconnect ( this ) ;
}
void AsyncWebServerRequest : : _addParam ( AsyncWebParameter * p ) {
2016-11-27 07:42:09 -08:00
_params . add ( p ) ;
2016-02-08 16:32:14 -08:00
}
2015-12-19 08:53:33 -08:00
2016-11-27 07:42:09 -08:00
void AsyncWebServerRequest : : _addGetParams ( const String & params ) {
2016-09-23 03:48:35 -07:00
size_t start = 0 ;
2016-06-25 12:04:06 -07:00
while ( start < params . length ( ) ) {
int end = params . indexOf ( ' & ' , start ) ;
if ( end < 0 ) end = params . length ( ) ;
int equal = params . indexOf ( ' = ' , start ) ;
if ( equal < 0 | | equal > end ) equal = end ;
String name = params . substring ( start , equal ) ;
String value = equal + 1 < end ? params . substring ( equal + 1 , end ) : String ( ) ;
_addParam ( new AsyncWebParameter ( name , value ) ) ;
start = end + 1 ;
2015-12-19 08:53:33 -08:00
}
}
bool AsyncWebServerRequest : : _parseReqHead ( ) {
2016-06-17 07:42:47 -07:00
// Split the head into method, url and version
int index = _temp . indexOf ( ' ' ) ;
String m = _temp . substring ( 0 , index ) ;
index = _temp . indexOf ( ' ' , index + 1 ) ;
String u = _temp . substring ( m . length ( ) + 1 , index ) ;
_temp = _temp . substring ( index + 1 ) ;
2015-12-19 08:53:33 -08:00
if ( m = = " GET " ) {
_method = HTTP_GET ;
} else if ( m = = " POST " ) {
_method = HTTP_POST ;
} else if ( m = = " DELETE " ) {
_method = HTTP_DELETE ;
} else if ( m = = " PUT " ) {
_method = HTTP_PUT ;
} else if ( m = = " PATCH " ) {
_method = HTTP_PATCH ;
} else if ( m = = " HEAD " ) {
_method = HTTP_HEAD ;
} else if ( m = = " OPTIONS " ) {
_method = HTTP_OPTIONS ;
}
2016-05-12 14:41:21 -07:00
u = urlDecode ( u ) ;
2015-12-19 08:53:33 -08:00
String g = String ( ) ;
2016-06-17 07:42:47 -07:00
index = u . indexOf ( ' ? ' ) ;
if ( index > 0 ) {
2016-06-25 12:04:06 -07:00
g = u . substring ( index + 1 ) ;
2016-06-17 07:42:47 -07:00
u = u . substring ( 0 , index ) ;
2015-12-19 08:53:33 -08:00
}
_url = u ;
2016-06-25 12:04:06 -07:00
_addGetParams ( g ) ;
2015-12-19 08:53:33 -08:00
2016-06-29 06:20:03 -07:00
if ( ! _temp . startsWith ( " HTTP/1.0 " ) )
2016-01-27 08:46:49 -08:00
_version = 1 ;
2016-06-25 12:04:06 -07:00
2015-12-19 08:53:33 -08:00
_temp = String ( ) ;
return true ;
}
bool AsyncWebServerRequest : : _parseReqHeader ( ) {
2016-06-17 07:42:47 -07:00
int index = _temp . indexOf ( ' : ' ) ;
if ( index ) {
String name = _temp . substring ( 0 , index ) ;
String value = _temp . substring ( index + 2 ) ;
2016-09-02 03:52:32 -07:00
if ( name . equalsIgnoreCase ( " Host " ) ) {
2016-06-17 07:42:47 -07:00
_host = value ;
2016-06-25 12:04:06 -07:00
_server - > _rewriteRequest ( this ) ;
_server - > _attachHandler ( this ) ;
2016-09-02 03:52:32 -07:00
} else if ( name . equalsIgnoreCase ( " Content-Type " ) ) {
2016-06-17 07:42:47 -07:00
if ( value . startsWith ( " multipart/ " ) ) {
_boundary = value . substring ( value . indexOf ( ' = ' ) + 1 ) ;
_contentType = value . substring ( 0 , value . indexOf ( ' ; ' ) ) ;
2015-12-19 08:53:33 -08:00
_isMultipart = true ;
} else {
2016-06-17 07:42:47 -07:00
_contentType = value ;
2015-12-19 08:53:33 -08:00
}
2016-09-02 03:52:32 -07:00
} else if ( name . equalsIgnoreCase ( " Content-Length " ) ) {
2016-06-17 07:42:47 -07:00
_contentLength = atoi ( value . c_str ( ) ) ;
2016-09-02 03:52:32 -07:00
} else if ( name . equalsIgnoreCase ( " Expect " ) & & value = = " 100-continue " ) {
2015-12-19 08:53:33 -08:00
_expectingContinue = true ;
2016-09-02 03:52:32 -07:00
} else if ( name . equalsIgnoreCase ( " Authorization " ) ) {
if ( value . length ( ) > 5 & & value . substring ( 0 , 5 ) . equalsIgnoreCase ( " Basic " ) ) {
2016-06-17 07:42:47 -07:00
_authorization = value . substring ( 6 ) ;
2016-09-02 03:52:32 -07:00
} else if ( value . length ( ) > 6 & & value . substring ( 0 , 6 ) . equalsIgnoreCase ( " Digest " ) ) {
2016-06-29 06:20:03 -07:00
_isDigest = true ;
_authorization = value . substring ( 7 ) ;
2015-12-19 08:53:33 -08:00
}
} else {
2016-11-27 07:42:09 -08:00
if ( _interestingHeaders . containsIgnoreCase ( name ) | | _interestingHeaders . containsIgnoreCase ( " ANY " ) ) {
_headers . add ( new AsyncWebHeader ( name , value ) ) ;
2016-06-17 07:42:47 -07:00
}
2015-12-19 08:53:33 -08:00
}
}
_temp = String ( ) ;
return true ;
}
void AsyncWebServerRequest : : _parsePlainPostChar ( uint8_t data ) {
2016-01-21 09:28:29 -08:00
if ( data & & ( char ) data ! = ' & ' )
2015-12-19 08:53:33 -08:00
_temp + = ( char ) data ;
2016-01-21 09:28:29 -08:00
if ( ! data | | ( char ) data = = ' & ' | | _parsedLength = = _contentLength ) {
2016-01-22 02:58:44 -08:00
_temp = urlDecode ( _temp ) ;
2016-01-21 09:28:29 -08:00
String name = " body " ;
String value = _temp ;
2016-01-21 09:32:40 -08:00
if ( ! _temp . startsWith ( " { " ) & & ! _temp . startsWith ( " [ " ) & & _temp . indexOf ( ' = ' ) > 0 ) {
2015-12-19 08:53:33 -08:00
name = _temp . substring ( 0 , _temp . indexOf ( ' = ' ) ) ;
value = _temp . substring ( _temp . indexOf ( ' = ' ) + 1 ) ;
}
_addParam ( new AsyncWebParameter ( name , value , true ) ) ;
_temp = String ( ) ;
}
}
2016-02-08 16:32:14 -08:00
void AsyncWebServerRequest : : _handleUploadByte ( uint8_t data , bool last ) {
_itemBuffer [ _itemBufferIndex + + ] = data ;
2016-05-12 14:01:42 -07:00
2016-05-12 14:19:50 -07:00
if ( last | | _itemBufferIndex = = 1460 ) {
2016-06-29 06:20:03 -07:00
//check if authenticated before calling the upload
2016-02-08 16:32:14 -08:00
if ( _handler )
_handler - > handleUpload ( this , _itemFilename , _itemSize - _itemBufferIndex , _itemBuffer , _itemBufferIndex , false ) ;
_itemBufferIndex = 0 ;
}
}
2015-12-19 08:53:33 -08:00
enum {
EXPECT_BOUNDARY ,
PARSE_HEADERS ,
WAIT_FOR_RETURN1 ,
EXPECT_FEED1 ,
EXPECT_DASH1 ,
EXPECT_DASH2 ,
BOUNDARY_OR_DATA ,
DASH3_OR_RETURN2 ,
EXPECT_FEED2 ,
PARSING_FINISHED ,
PARSE_ERROR
} ;
void AsyncWebServerRequest : : _parseMultipartPostByte ( uint8_t data , bool last ) {
# define itemWriteByte(b) do { _itemSize++; if(_itemIsFile) _handleUploadByte(b, last); else _itemValue+=(char)(b); } while(0)
2015-12-21 15:41:57 -08:00
2015-12-19 08:53:33 -08:00
if ( ! _parsedLength ) {
_multiParseState = EXPECT_BOUNDARY ;
_temp = String ( ) ;
_itemName = String ( ) ;
_itemFilename = String ( ) ;
_itemType = String ( ) ;
}
2016-05-12 14:01:42 -07:00
if ( _multiParseState = = WAIT_FOR_RETURN1 ) {
if ( data ! = ' \r ' ) {
itemWriteByte ( data ) ;
} else {
_multiParseState = EXPECT_FEED1 ;
}
} else if ( _multiParseState = = EXPECT_BOUNDARY ) {
2015-12-19 08:53:33 -08:00
if ( _parsedLength < 2 & & data ! = ' - ' ) {
_multiParseState = PARSE_ERROR ;
return ;
} else if ( _parsedLength - 2 < _boundary . length ( ) & & _boundary . c_str ( ) [ _parsedLength - 2 ] ! = data ) {
_multiParseState = PARSE_ERROR ;
return ;
} else if ( _parsedLength - 2 = = _boundary . length ( ) & & data ! = ' \r ' ) {
_multiParseState = PARSE_ERROR ;
return ;
} else if ( _parsedLength - 3 = = _boundary . length ( ) ) {
if ( data ! = ' \n ' ) {
_multiParseState = PARSE_ERROR ;
return ;
}
_multiParseState = PARSE_HEADERS ;
_itemIsFile = false ;
}
} else if ( _multiParseState = = PARSE_HEADERS ) {
if ( ( char ) data ! = ' \r ' & & ( char ) data ! = ' \n ' )
_temp + = ( char ) data ;
if ( ( char ) data = = ' \n ' ) {
if ( _temp . length ( ) ) {
2016-09-03 13:30:14 -07:00
if ( _temp . length ( ) > 12 & & _temp . substring ( 0 , 12 ) . equalsIgnoreCase ( " Content-Type " ) ) {
2015-12-19 08:53:33 -08:00
_itemType = _temp . substring ( 14 ) ;
_itemIsFile = true ;
2016-09-03 13:30:14 -07:00
} else if ( _temp . length ( ) > 19 & & _temp . substring ( 0 , 19 ) . equalsIgnoreCase ( " Content-Disposition " ) ) {
2015-12-19 08:53:33 -08:00
_temp = _temp . substring ( _temp . indexOf ( ' ; ' ) + 2 ) ;
while ( _temp . indexOf ( ' ; ' ) > 0 ) {
String name = _temp . substring ( 0 , _temp . indexOf ( ' = ' ) ) ;
String nameVal = _temp . substring ( _temp . indexOf ( ' = ' ) + 2 , _temp . indexOf ( ' ; ' ) - 1 ) ;
if ( name = = " name " ) {
_itemName = nameVal ;
} else if ( name = = " filename " ) {
_itemFilename = nameVal ;
_itemIsFile = true ;
}
_temp = _temp . substring ( _temp . indexOf ( ' ; ' ) + 2 ) ;
}
String name = _temp . substring ( 0 , _temp . indexOf ( ' = ' ) ) ;
String nameVal = _temp . substring ( _temp . indexOf ( ' = ' ) + 2 , _temp . length ( ) - 1 ) ;
if ( name = = " name " ) {
_itemName = nameVal ;
} else if ( name = = " filename " ) {
_itemFilename = nameVal ;
_itemIsFile = true ;
}
}
_temp = String ( ) ;
} else {
_multiParseState = WAIT_FOR_RETURN1 ;
//value starts from here
_itemSize = 0 ;
_itemStartIndex = _parsedLength ;
_itemValue = String ( ) ;
if ( _itemIsFile ) {
if ( _itemBuffer )
2015-12-21 15:41:57 -08:00
free ( _itemBuffer ) ;
_itemBuffer = ( uint8_t * ) malloc ( 1460 ) ;
2016-05-12 14:01:42 -07:00
if ( _itemBuffer = = NULL ) {
_multiParseState = PARSE_ERROR ;
return ;
}
2015-12-19 08:53:33 -08:00
_itemBufferIndex = 0 ;
}
}
}
} else if ( _multiParseState = = EXPECT_FEED1 ) {
if ( data ! = ' \n ' ) {
_multiParseState = WAIT_FOR_RETURN1 ;
2016-05-19 14:55:19 -07:00
itemWriteByte ( ' \r ' ) ; _parseMultipartPostByte ( data , last ) ;
2015-12-19 08:53:33 -08:00
} else {
_multiParseState = EXPECT_DASH1 ;
}
} else if ( _multiParseState = = EXPECT_DASH1 ) {
if ( data ! = ' - ' ) {
_multiParseState = WAIT_FOR_RETURN1 ;
2016-05-19 14:55:19 -07:00
itemWriteByte ( ' \r ' ) ; itemWriteByte ( ' \n ' ) ; _parseMultipartPostByte ( data , last ) ;
2015-12-19 08:53:33 -08:00
} else {
_multiParseState = EXPECT_DASH2 ;
}
} else if ( _multiParseState = = EXPECT_DASH2 ) {
if ( data ! = ' - ' ) {
_multiParseState = WAIT_FOR_RETURN1 ;
2016-05-19 14:55:19 -07:00
itemWriteByte ( ' \r ' ) ; itemWriteByte ( ' \n ' ) ; itemWriteByte ( ' - ' ) ; _parseMultipartPostByte ( data , last ) ;
2015-12-19 08:53:33 -08:00
} else {
_multiParseState = BOUNDARY_OR_DATA ;
_boundaryPosition = 0 ;
}
} else if ( _multiParseState = = BOUNDARY_OR_DATA ) {
if ( _boundaryPosition < _boundary . length ( ) & & _boundary . c_str ( ) [ _boundaryPosition ] ! = data ) {
_multiParseState = WAIT_FOR_RETURN1 ;
itemWriteByte ( ' \r ' ) ; itemWriteByte ( ' \n ' ) ; itemWriteByte ( ' - ' ) ; itemWriteByte ( ' - ' ) ;
uint8_t i ;
for ( i = 0 ; i < _boundaryPosition ; i + + )
itemWriteByte ( _boundary . c_str ( ) [ i ] ) ;
2016-05-19 14:55:19 -07:00
_parseMultipartPostByte ( data , last ) ;
2015-12-19 08:53:33 -08:00
} else if ( _boundaryPosition = = _boundary . length ( ) - 1 ) {
_multiParseState = DASH3_OR_RETURN2 ;
if ( ! _itemIsFile ) {
_addParam ( new AsyncWebParameter ( _itemName , _itemValue , true ) ) ;
} else {
if ( _itemSize ) {
2016-06-29 06:20:03 -07:00
//check if authenticated before calling the upload
2015-12-19 08:53:33 -08:00
if ( _handler ) _handler - > handleUpload ( this , _itemFilename , _itemSize - _itemBufferIndex , _itemBuffer , _itemBufferIndex , true ) ;
_itemBufferIndex = 0 ;
_addParam ( new AsyncWebParameter ( _itemName , _itemFilename , true , true , _itemSize ) ) ;
}
2015-12-21 15:41:57 -08:00
free ( _itemBuffer ) ;
2016-11-29 13:12:52 -08:00
_itemBuffer = NULL ;
2015-12-19 08:53:33 -08:00
}
} else {
_boundaryPosition + + ;
}
} else if ( _multiParseState = = DASH3_OR_RETURN2 ) {
2016-01-21 06:39:12 -08:00
if ( data = = ' - ' & & ( _contentLength - _parsedLength - 4 ) ! = 0 ) {
2016-01-22 02:58:44 -08:00
os_printf ( " ERROR: The parser got to the end of the POST but is expecting %u bytes more! \n Drop an issue so we can have more info on the matter! \n " , _contentLength - _parsedLength - 4 ) ;
2016-01-21 06:39:12 -08:00
_contentLength = _parsedLength + 4 ; //lets close the request gracefully
}
2015-12-19 08:53:33 -08:00
if ( data = = ' \r ' ) {
_multiParseState = EXPECT_FEED2 ;
} else if ( data = = ' - ' & & _contentLength = = ( _parsedLength + 4 ) ) {
_multiParseState = PARSING_FINISHED ;
} else {
_multiParseState = WAIT_FOR_RETURN1 ;
itemWriteByte ( ' \r ' ) ; itemWriteByte ( ' \n ' ) ; itemWriteByte ( ' - ' ) ; itemWriteByte ( ' - ' ) ;
uint8_t i ; for ( i = 0 ; i < _boundary . length ( ) ; i + + ) itemWriteByte ( _boundary . c_str ( ) [ i ] ) ;
2016-05-19 14:55:19 -07:00
_parseMultipartPostByte ( data , last ) ;
2015-12-19 08:53:33 -08:00
}
} else if ( _multiParseState = = EXPECT_FEED2 ) {
if ( data = = ' \n ' ) {
_multiParseState = PARSE_HEADERS ;
_itemIsFile = false ;
} else {
_multiParseState = WAIT_FOR_RETURN1 ;
itemWriteByte ( ' \r ' ) ; itemWriteByte ( ' \n ' ) ; itemWriteByte ( ' - ' ) ; itemWriteByte ( ' - ' ) ;
uint8_t i ; for ( i = 0 ; i < _boundary . length ( ) ; i + + ) itemWriteByte ( _boundary . c_str ( ) [ i ] ) ;
2016-05-19 14:55:19 -07:00
itemWriteByte ( ' \r ' ) ; _parseMultipartPostByte ( data , last ) ;
2015-12-19 08:53:33 -08:00
}
}
}
2016-02-08 16:32:14 -08:00
void AsyncWebServerRequest : : _parseLine ( ) {
if ( _parseState = = PARSE_REQ_START ) {
if ( ! _temp . length ( ) ) {
_parseState = PARSE_REQ_FAIL ;
_client - > close ( ) ;
} else {
_parseReqHead ( ) ;
_parseState = PARSE_REQ_HEADERS ;
}
return ;
}
2015-12-19 08:53:33 -08:00
2016-02-08 16:32:14 -08:00
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 ) ) ;
}
2016-06-29 06:20:03 -07:00
//check handler for authentication
2016-02-08 16:32:14 -08:00
if ( _contentLength ) {
_parseState = PARSE_REQ_BODY ;
} else {
_parseState = PARSE_REQ_END ;
if ( _handler ) _handler - > handleRequest ( this ) ;
else send ( 501 ) ;
}
} else _parseReqHeader ( ) ;
}
}
2015-12-19 08:53:33 -08:00
2016-11-27 07:42:09 -08:00
size_t AsyncWebServerRequest : : headers ( ) const {
return _headers . length ( ) ;
2016-02-08 16:32:14 -08:00
}
2016-11-27 07:42:09 -08:00
bool AsyncWebServerRequest : : hasHeader ( const String & name ) const {
for ( const auto & h : _headers ) {
if ( h - > name ( ) . equalsIgnoreCase ( name ) ) {
2016-02-08 16:32:14 -08:00
return true ;
2016-11-27 07:42:09 -08:00
}
2016-02-08 16:32:14 -08:00
}
return false ;
}
2017-03-05 10:06:57 -08:00
bool AsyncWebServerRequest : : hasHeader ( const __FlashStringHelper * data ) const {
PGM_P p = reinterpret_cast < PGM_P > ( data ) ;
size_t n = 0 ;
while ( 1 ) {
if ( pgm_read_byte ( p + n ) = = 0 ) break ;
n + = 1 ;
}
char * name = ( char * ) malloc ( n + 1 ) ;
name [ n ] = 0 ;
if ( name ) {
for ( size_t b = 0 ; b < n ; b + + )
name [ b ] = pgm_read_byte ( p + + ) ;
bool result = hasHeader ( String ( name ) ) ;
free ( name ) ;
return result ;
} else {
return false ;
}
}
2016-11-27 07:42:09 -08:00
AsyncWebHeader * AsyncWebServerRequest : : getHeader ( const String & name ) const {
for ( const auto & h : _headers ) {
if ( h - > name ( ) . equalsIgnoreCase ( name ) ) {
2016-02-08 16:32:14 -08:00
return h ;
2016-11-27 07:42:09 -08:00
}
2016-02-08 16:32:14 -08:00
}
2016-11-27 07:42:09 -08:00
return nullptr ;
2016-02-08 16:32:14 -08:00
}
2017-03-05 10:06:57 -08:00
AsyncWebHeader * AsyncWebServerRequest : : getHeader ( const __FlashStringHelper * data ) const {
PGM_P p = reinterpret_cast < PGM_P > ( data ) ;
size_t n = strlen_P ( p ) ;
char * name = ( char * ) malloc ( n + 1 ) ;
if ( name ) {
strcpy_P ( name , p ) ;
AsyncWebHeader * result = getHeader ( String ( name ) ) ;
free ( name ) ;
return result ;
} else {
return nullptr ;
}
}
2016-11-27 07:42:09 -08:00
AsyncWebHeader * AsyncWebServerRequest : : getHeader ( size_t num ) const {
auto header = _headers . nth ( num ) ;
return header ? * header : nullptr ;
2016-02-08 16:32:14 -08:00
}
2016-11-27 07:42:09 -08:00
size_t AsyncWebServerRequest : : params ( ) const {
return _params . length ( ) ;
2016-02-08 16:32:14 -08:00
}
2016-11-27 07:42:09 -08:00
bool AsyncWebServerRequest : : hasParam ( const String & name , bool post , bool file ) const {
for ( const auto & p : _params ) {
if ( p - > name ( ) = = name & & p - > isPost ( ) = = post & & p - > isFile ( ) = = file ) {
2016-02-08 16:32:14 -08:00
return true ;
2016-11-27 07:42:09 -08:00
}
2016-02-08 16:32:14 -08:00
}
return false ;
}
2017-03-05 10:06:57 -08:00
bool AsyncWebServerRequest : : hasParam ( const __FlashStringHelper * data , bool post , bool file ) const {
PGM_P p = reinterpret_cast < PGM_P > ( data ) ;
size_t n = strlen_P ( p ) ;
char * name = ( char * ) malloc ( n + 1 ) ;
name [ n ] = 0 ;
if ( name ) {
strcpy_P ( name , p ) ;
bool result = hasParam ( name , post , file ) ;
free ( name ) ;
return result ;
} else {
return false ;
}
}
2016-11-27 07:42:09 -08:00
AsyncWebParameter * AsyncWebServerRequest : : getParam ( const String & name , bool post , bool file ) const {
for ( const auto & p : _params ) {
if ( p - > name ( ) = = name & & p - > isPost ( ) = = post & & p - > isFile ( ) = = file ) {
return p ;
}
2016-02-08 16:32:14 -08:00
}
2016-11-27 07:42:09 -08:00
return nullptr ;
2016-02-08 16:32:14 -08:00
}
2017-03-05 10:06:57 -08:00
AsyncWebParameter * AsyncWebServerRequest : : getParam ( const __FlashStringHelper * data , bool post , bool file ) const {
PGM_P p = reinterpret_cast < PGM_P > ( data ) ;
size_t n = strlen_P ( p ) ;
char * name = ( char * ) malloc ( n + 1 ) ;
if ( name ) {
strcpy_P ( name , p ) ;
AsyncWebParameter * result = getParam ( name , post , file ) ;
free ( name ) ;
return result ;
} else {
return nullptr ;
}
}
2016-11-27 07:42:09 -08:00
AsyncWebParameter * AsyncWebServerRequest : : getParam ( size_t num ) const {
auto param = _params . nth ( num ) ;
return param ? * param : nullptr ;
2016-02-08 16:32:14 -08:00
}
2016-11-27 07:42:09 -08:00
void AsyncWebServerRequest : : addInterestingHeader ( const String & name ) {
if ( ! _interestingHeaders . containsIgnoreCase ( name ) )
_interestingHeaders . add ( name ) ;
2016-02-08 16:32:14 -08:00
}
void AsyncWebServerRequest : : send ( AsyncWebServerResponse * response ) {
_response = response ;
2016-04-08 07:43:16 -07:00
if ( _response = = NULL ) {
_client - > close ( true ) ;
_onDisconnect ( ) ;
return ;
}
2016-04-11 11:42:37 -07:00
if ( ! _response - > _sourceValid ( ) ) {
delete response ;
_response = NULL ;
2016-04-08 07:43:16 -07:00
send ( 500 ) ;
2016-04-11 11:42:37 -07:00
}
2016-04-08 07:43:16 -07:00
else
_response - > _respond ( this ) ;
2016-02-08 16:32:14 -08:00
}
2016-11-27 07:42:09 -08:00
AsyncWebServerResponse * AsyncWebServerRequest : : beginResponse ( int code , const String & contentType , const String & content ) {
2016-02-08 16:32:14 -08:00
return new AsyncBasicResponse ( code , contentType , content ) ;
}
2016-11-27 07:42:09 -08:00
AsyncWebServerResponse * AsyncWebServerRequest : : beginResponse ( FS & fs , const String & path , const String & contentType , bool download ) {
2016-02-08 16:32:14 -08:00
if ( fs . exists ( path ) | | ( ! download & & fs . exists ( path + " .gz " ) ) )
return new AsyncFileResponse ( fs , path , contentType , download ) ;
return NULL ;
}
2016-11-27 07:42:09 -08:00
AsyncWebServerResponse * AsyncWebServerRequest : : beginResponse ( File content , const String & path , const String & contentType , bool download ) {
2016-06-16 15:43:59 -07:00
if ( content = = true )
2016-06-16 16:23:18 -07:00
return new AsyncFileResponse ( content , path , contentType , download ) ;
2016-06-16 15:43:59 -07:00
return NULL ;
}
2016-11-27 07:42:09 -08:00
AsyncWebServerResponse * AsyncWebServerRequest : : beginResponse ( Stream & stream , const String & contentType , size_t len ) {
2016-02-08 16:32:14 -08:00
return new AsyncStreamResponse ( stream , contentType , len ) ;
}
2016-11-27 07:42:09 -08:00
AsyncWebServerResponse * AsyncWebServerRequest : : beginResponse ( const String & contentType , size_t len , AwsResponseFiller callback ) {
2016-02-08 16:32:14 -08:00
return new AsyncCallbackResponse ( contentType , len , callback ) ;
}
2016-11-27 07:42:09 -08:00
AsyncWebServerResponse * AsyncWebServerRequest : : beginChunkedResponse ( const String & contentType , AwsResponseFiller callback ) {
2016-02-08 16:32:14 -08:00
if ( _version )
return new AsyncChunkedResponse ( contentType , callback ) ;
return new AsyncCallbackResponse ( contentType , 0 , callback ) ;
}
2016-11-27 07:42:09 -08:00
AsyncResponseStream * AsyncWebServerRequest : : beginResponseStream ( const String & contentType , size_t bufferSize ) {
2016-02-08 16:32:14 -08:00
return new AsyncResponseStream ( contentType , bufferSize ) ;
}
2016-11-27 07:42:09 -08:00
AsyncWebServerResponse * AsyncWebServerRequest : : beginResponse_P ( int code , const String & contentType , const uint8_t * content , size_t len ) {
2016-07-21 02:25:20 -07:00
return new AsyncProgmemResponse ( code , contentType , content , len ) ;
}
2016-11-27 07:42:09 -08:00
AsyncWebServerResponse * AsyncWebServerRequest : : beginResponse_P ( int code , const String & contentType , PGM_P content ) {
2016-07-21 02:25:20 -07:00
return beginResponse_P ( code , contentType , ( const uint8_t * ) content , strlen_P ( content ) ) ;
}
2016-11-27 07:42:09 -08:00
void AsyncWebServerRequest : : send ( int code , const String & contentType , const String & content ) {
2016-02-08 16:32:14 -08:00
send ( beginResponse ( code , contentType , content ) ) ;
}
2016-11-27 07:42:09 -08:00
void AsyncWebServerRequest : : send ( FS & fs , const String & path , const String & contentType , bool download ) {
2016-02-08 16:32:14 -08:00
if ( fs . exists ( path ) | | ( ! download & & fs . exists ( path + " .gz " ) ) ) {
send ( beginResponse ( fs , path , contentType , download ) ) ;
} else send ( 404 ) ;
}
2016-11-27 07:42:09 -08:00
void AsyncWebServerRequest : : send ( File content , const String & path , const String & contentType , bool download ) {
2016-06-16 15:43:59 -07:00
if ( content = = true ) {
2016-06-16 16:23:18 -07:00
send ( beginResponse ( content , path , contentType , download ) ) ;
2016-06-16 15:43:59 -07:00
} else send ( 404 ) ;
}
2016-11-27 07:42:09 -08:00
void AsyncWebServerRequest : : send ( Stream & stream , const String & contentType , size_t len ) {
2016-02-08 16:32:14 -08:00
send ( beginResponse ( stream , contentType , len ) ) ;
}
2016-11-27 07:42:09 -08:00
void AsyncWebServerRequest : : send ( const String & contentType , size_t len , AwsResponseFiller callback ) {
2016-02-08 16:32:14 -08:00
send ( beginResponse ( contentType , len , callback ) ) ;
}
2016-11-27 07:42:09 -08:00
void AsyncWebServerRequest : : sendChunked ( const String & contentType , AwsResponseFiller callback ) {
2016-02-08 16:32:14 -08:00
send ( beginChunkedResponse ( contentType , callback ) ) ;
}
2016-11-27 07:42:09 -08:00
void AsyncWebServerRequest : : send_P ( int code , const String & contentType , const uint8_t * content , size_t len ) {
2016-07-21 02:25:20 -07:00
send ( beginResponse_P ( code , contentType , content , len ) ) ;
}
2016-11-27 07:42:09 -08:00
void AsyncWebServerRequest : : send_P ( int code , const String & contentType , PGM_P content ) {
2016-07-21 02:25:20 -07:00
send ( beginResponse_P ( code , contentType , content ) ) ;
}
2016-11-27 07:42:09 -08:00
void AsyncWebServerRequest : : redirect ( const String & url ) {
2016-06-26 06:20:21 -07:00
AsyncWebServerResponse * response = beginResponse ( 302 ) ;
response - > addHeader ( " Location " , url ) ;
send ( response ) ;
}
2016-06-29 06:20:03 -07:00
bool AsyncWebServerRequest : : authenticate ( const char * username , const char * password , const char * realm , bool passwordIsHash ) {
2016-02-08 16:32:14 -08:00
if ( _authorization . length ( ) ) {
2016-06-29 06:20:03 -07:00
if ( _isDigest )
return checkDigestAuthentication ( _authorization . c_str ( ) , methodToString ( ) , username , password , realm , passwordIsHash , NULL , NULL , NULL ) ;
else if ( ! passwordIsHash )
return checkBasicAuthentication ( _authorization . c_str ( ) , username , password ) ;
else
return _authorization . equals ( password ) ;
2016-02-08 16:32:14 -08:00
}
return false ;
}
bool AsyncWebServerRequest : : authenticate ( const char * hash ) {
2016-06-29 06:20:03 -07:00
if ( ! _authorization . length ( ) | | hash = = NULL )
return false ;
if ( _isDigest ) {
String hStr = String ( hash ) ;
int separator = hStr . indexOf ( " : " ) ;
if ( separator < = 0 )
return false ;
String username = hStr . substring ( 0 , separator ) ;
hStr = hStr . substring ( separator + 1 ) ;
separator = hStr . indexOf ( " : " ) ;
if ( separator < = 0 )
return false ;
String realm = hStr . substring ( 0 , separator ) ;
hStr = hStr . substring ( separator + 1 ) ;
return checkDigestAuthentication ( _authorization . c_str ( ) , methodToString ( ) , username . c_str ( ) , hStr . c_str ( ) , realm . c_str ( ) , true , NULL , NULL , NULL ) ;
}
return ( _authorization . equals ( hash ) ) ;
2016-02-08 16:32:14 -08:00
}
2016-06-29 06:20:03 -07:00
void AsyncWebServerRequest : : requestAuthentication ( const char * realm , bool isDigest ) {
2016-02-08 16:32:14 -08:00
AsyncWebServerResponse * r = beginResponse ( 401 ) ;
2016-06-29 06:20:03 -07:00
if ( ! isDigest & & realm = = NULL ) {
r - > addHeader ( " WWW-Authenticate " , " Basic realm= \" Login Required \" " ) ;
} else if ( ! isDigest ) {
String header = " Basic realm= \" " ;
header . concat ( realm ) ;
header . concat ( " \" " ) ;
r - > addHeader ( " WWW-Authenticate " , header ) ;
} else {
String header = " Digest " ;
header . concat ( requestDigestAuthentication ( realm ) ) ;
r - > addHeader ( " WWW-Authenticate " , header ) ;
}
2016-02-08 16:32:14 -08:00
send ( r ) ;
}
2016-11-27 07:42:09 -08:00
bool AsyncWebServerRequest : : hasArg ( const char * name ) const {
for ( const auto & arg : _params ) {
if ( arg - > name ( ) = = name ) {
2016-02-08 16:32:14 -08:00
return true ;
2016-11-27 07:42:09 -08:00
}
2016-02-08 16:32:14 -08:00
}
return false ;
}
2015-12-19 08:53:33 -08:00
2017-03-05 10:06:57 -08:00
bool AsyncWebServerRequest : : hasArg ( const __FlashStringHelper * data ) const {
PGM_P p = reinterpret_cast < PGM_P > ( data ) ;
size_t n = strlen_P ( p ) ;
char * name = ( char * ) malloc ( n + 1 ) ;
if ( name ) {
strcpy_P ( name , p ) ;
bool result = hasArg ( name ) ;
free ( name ) ;
return result ;
} else {
return false ;
}
}
2016-11-27 07:42:09 -08:00
const String & AsyncWebServerRequest : : arg ( const String & name ) const {
for ( const auto & arg : _params ) {
if ( arg - > name ( ) = = name ) {
return arg - > value ( ) ;
}
2016-02-08 16:32:14 -08:00
}
2016-11-27 07:42:09 -08:00
return SharedEmptyString ;
2016-02-08 16:32:14 -08:00
}
2017-03-05 10:06:57 -08:00
const String & AsyncWebServerRequest : : arg ( const __FlashStringHelper * data ) const {
PGM_P p = reinterpret_cast < PGM_P > ( data ) ;
size_t n = strlen_P ( p ) ;
char * name = ( char * ) malloc ( n + 1 ) ;
if ( name ) {
strcpy ( name , p ) ;
const String & result = arg ( String ( name ) ) ;
free ( name ) ;
return result ;
} else {
return SharedEmptyString ;
}
}
2016-11-27 07:42:09 -08:00
const String & AsyncWebServerRequest : : arg ( size_t i ) const {
2016-02-08 16:32:14 -08:00
return getParam ( i ) - > value ( ) ;
}
2015-12-19 08:53:33 -08:00
2016-11-27 07:42:09 -08:00
const String & AsyncWebServerRequest : : argName ( size_t i ) const {
2016-02-08 16:32:14 -08:00
return getParam ( i ) - > name ( ) ;
}
2016-11-27 07:42:09 -08:00
const String & AsyncWebServerRequest : : header ( const char * name ) const {
2016-02-08 16:32:14 -08:00
AsyncWebHeader * h = getHeader ( String ( name ) ) ;
2016-11-27 07:42:09 -08:00
return h ? h - > value ( ) : SharedEmptyString ;
2016-02-08 16:32:14 -08:00
}
2017-03-05 10:06:57 -08:00
const String & AsyncWebServerRequest : : header ( const __FlashStringHelper * data ) const {
PGM_P p = reinterpret_cast < PGM_P > ( data ) ;
size_t n = strlen_P ( p ) ;
char * name = ( char * ) malloc ( n + 1 ) ;
if ( name ) {
strcpy_P ( name , p ) ;
const String & result = header ( ( const char * ) name ) ;
free ( name ) ;
return result ;
} else {
return SharedEmptyString ;
}
} ;
2016-11-27 07:42:09 -08:00
const String & AsyncWebServerRequest : : header ( size_t i ) const {
2016-02-08 16:32:14 -08:00
AsyncWebHeader * h = getHeader ( i ) ;
2016-11-27 07:42:09 -08:00
return h ? h - > value ( ) : SharedEmptyString ;
2016-02-08 16:32:14 -08:00
}
2016-11-27 07:42:09 -08:00
const String & AsyncWebServerRequest : : headerName ( size_t i ) const {
2016-02-08 16:32:14 -08:00
AsyncWebHeader * h = getHeader ( i ) ;
2016-11-27 07:42:09 -08:00
return h ? h - > name ( ) : SharedEmptyString ;
2016-02-08 16:32:14 -08:00
}
2016-11-27 07:42:09 -08:00
String AsyncWebServerRequest : : urlDecode ( const String & text ) const {
2016-02-08 16:32:14 -08:00
char temp [ ] = " 0x00 " ;
unsigned int len = text . length ( ) ;
unsigned int i = 0 ;
2016-06-17 07:42:47 -07:00
String decoded = String ( ) ;
decoded . reserve ( len ) ; // Allocate the string internal buffer - never longer from source text
2016-02-08 16:32:14 -08:00
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 ) ;
2016-06-17 07:42:47 -07:00
} else if ( encodedChar = = ' + ' ) {
decodedChar = ' ' ;
2016-02-08 16:32:14 -08:00
} else {
2016-06-17 07:42:47 -07:00
decodedChar = encodedChar ; // normal ascii char
2016-02-08 16:32:14 -08:00
}
2016-06-17 07:42:47 -07:00
decoded . concat ( decodedChar ) ;
2016-02-08 16:32:14 -08:00
}
return decoded ;
}
2016-11-27 07:42:09 -08:00
const char * AsyncWebServerRequest : : methodToString ( ) const {
2016-02-08 16:32:14 -08:00
if ( _method = = HTTP_ANY ) return " ANY " ;
2016-08-19 12:21:08 -07:00
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 " ;
2016-02-08 16:32:14 -08:00
return " UNKNOWN " ;
}