2015-12-19 18:53:33 +02:00
/*
2016-02-09 02:56:01 +02:00
Asynchronous WebServer library for Espressif MCUs
2015-12-19 18:53:33 +02:00
2016-02-09 02:56:01 +02: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 18:53:33 +02:00
#include "ESPAsyncWebServer.h"
2016-02-09 02:56:01 +02:00
#include "WebResponseImpl.h"
2016-06-29 16:20:03 +03:00
#include "WebAuthentication.h"
2015-12-19 18:53:33 +02:00
2016-01-22 18:09:05 +02:00
#ifndef ESP8266
#define os_strlen strlen
#endif
2016-11-27 17:42:09 +02:00
static const String SharedEmptyString = String ();
2015-12-22 12:42:07 +02:00
#define __is_param_char(c) ((c) && ((c) != '{') && ((c) != '[') && ((c) != '&') && ((c) != '='))
2015-12-19 18:53:33 +02:00
enum { PARSE_REQ_START , PARSE_REQ_HEADERS , PARSE_REQ_BODY , PARSE_REQ_END , PARSE_REQ_FAIL };
2016-02-09 02:32:14 +02: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 ()
2017-08-18 17:52:21 +03:00
, _reqconntype ( RCT_HTTP )
2016-06-29 16:20:03 +03:00
, _isDigest ( false )
2016-02-09 02:32:14 +02:00
, _isMultipart ( false )
, _isPlainPost ( false )
, _expectingContinue ( false )
, _contentLength ( 0 )
, _parsedLength ( 0 )
2016-11-27 17:42:09 +02:00
, _headers ( LinkedList < AsyncWebHeader *> ([]( AsyncWebHeader * h ){ delete h ; }))
, _params ( LinkedList < AsyncWebParameter *> ([]( AsyncWebParameter * p ){ delete p ; }))
2016-02-09 02:32:14 +02:00
, _multiParseState ( 0 )
, _boundaryPosition ( 0 )
, _itemStartIndex ( 0 )
, _itemSize ( 0 )
, _itemName ()
, _itemFilename ()
, _itemType ()
, _itemValue ()
, _itemBuffer ( 0 )
, _itemBufferIndex ( 0 )
, _itemIsFile ( false )
2016-06-16 23:24:09 +03:00
, _tempObject ( NULL )
2016-02-09 02:32:14 +02: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-14 00:01:13 +03:00
c -> onDisconnect ([]( void * r , AsyncClient * c ){ AsyncWebServerRequest * req = ( AsyncWebServerRequest * ) r ; req -> _onDisconnect (); delete c ; }, this );
2016-02-09 02:32:14 +02: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 18:53:33 +02:00
}
2016-02-09 02:32:14 +02:00
AsyncWebServerRequest ::~ AsyncWebServerRequest (){
2016-11-27 17:42:09 +02:00
_headers . free ();
2015-12-19 18:53:33 +02:00
2016-11-27 17:42:09 +02:00
_params . free ();
2016-02-09 02:32:14 +02:00
2016-11-27 17:42:09 +02:00
_interestingHeaders . free ();
2016-02-09 02:32:14 +02:00
if ( _response != NULL ){
delete _response ;
}
2016-06-16 23:27:01 +03:00
if ( _tempObject != NULL ){
2016-06-17 01:53:21 +03:00
free ( _tempObject );
2016-06-16 23:09:58 +03:00
}
2016-09-23 13:48:35 +03:00
if ( _tempFile ){
_tempFile . close ();
}
2015-12-19 18:53:33 +02:00
}
void AsyncWebServerRequest :: _onData ( void * buf , size_t len ){
2017-09-07 15:02:46 -04:00
size_t i = 0 ;
2017-01-22 05:47:21 -05:00
while ( true ) {
2015-12-19 18:53:33 +02:00
if ( _parseState < PARSE_REQ_BODY ){
2016-06-17 15:42:47 +01:00
// Find new line in buf
char * str = ( char * ) buf ;
2017-08-18 17:52:21 +03:00
for ( i = 0 ; i < len ; i ++ ) {
if ( str [ i ] == '\n' ) {
break ;
}
}
2016-06-17 15:42:47 +01:00
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 05:47:21 -05:00
if ( ++ i < len ) {
// Still have more buffer to process
buf = str + i ;
len -= i ;
continue ;
}
2015-12-19 18:53:33 +02:00
}
} else if ( _parseState == PARSE_REQ_BODY ){
if ( _isMultipart ){
size_t i ;
for ( i = 0 ; i < len ; i ++ ){
2016-02-09 02:32:14 +02:00
_parseMultipartPostByte ((( uint8_t * ) buf )[ i ], i == len - 1 );
2015-12-19 18:53:33 +02:00
_parsedLength ++ ;
}
} else {
if ( _parsedLength == 0 ){
2016-01-21 18:41:48 +02:00
if ( _contentType . startsWith ( "application/x-www-form-urlencoded" )){
2015-12-19 18:53:33 +02: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 16:20:03 +03:00
//check if authenticated before calling the body
2015-12-19 18:53:33 +02: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-09 02:32:14 +02:00
_parsePlainPostChar ((( uint8_t * ) buf )[ i ]);
2015-12-19 18:53:33 +02:00
}
}
}
if ( _parsedLength == _contentLength ){
_parseState = PARSE_REQ_END ;
2016-06-29 16:20:03 +03:00
//check if authenticated before calling handleRequest and request auth instead
2015-12-19 18:53:33 +02:00
if ( _handler ) _handler -> handleRequest ( this );
else send ( 501 );
}
}
2017-01-22 05:47:21 -05:00
break ;
}
2015-12-19 18:53:33 +02:00
}
2017-08-18 17:52:21 +03:00
void AsyncWebServerRequest :: _removeNotInterestingHeaders (){
if ( _interestingHeaders . containsIgnoreCase ( "ANY" )) return ; // nothing to do
for ( const auto & header : _headers ){
if ( ! _interestingHeaders . containsIgnoreCase ( header -> name (). c_str ())){
_headers . remove ( header );
}
}
}
2016-02-09 02:32:14 +02:00
void AsyncWebServerRequest :: _onPoll (){
//os_printf("p\n");
2016-04-05 11:22:20 +03:00
if ( _response != NULL && _client != NULL && _client -> canSend () && ! _response -> _finished ()){
2016-02-09 02:32:14 +02: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 11:22:20 +03:00
2016-02-09 02:32:14 +02:00
}
void AsyncWebServerRequest :: _onTimeout ( uint32_t time ){
2017-09-07 22:01:58 +03:00
//os_printf("TIMEOUT: %u, state: %s\n", time, _client->stateToString());
2016-02-09 02:32:14 +02:00
_client -> close ();
}
void AsyncWebServerRequest :: _onDisconnect (){
//os_printf("d\n");
_server -> _handleDisconnect ( this );
}
void AsyncWebServerRequest :: _addParam ( AsyncWebParameter * p ){
2016-11-27 17:42:09 +02:00
_params . add ( p );
2016-02-09 02:32:14 +02:00
}
2015-12-19 18:53:33 +02:00
2016-11-27 17:42:09 +02:00
void AsyncWebServerRequest :: _addGetParams ( const String & params ){
2016-09-23 13:48:35 +03:00
size_t start = 0 ;
2016-06-25 20:04:06 +01: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 ();
2017-08-18 10:53:57 +02:00
_addParam ( new AsyncWebParameter ( urlDecode ( name ), urlDecode ( value )));
2016-06-25 20:04:06 +01:00
start = end + 1 ;
2015-12-19 18:53:33 +02:00
}
}
bool AsyncWebServerRequest :: _parseReqHead (){
2016-06-17 15:42:47 +01: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 18:53:33 +02: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 ;
}
String g = String ();
2016-06-17 15:42:47 +01:00
index = u . indexOf ( '?' );
if ( index > 0 ){
2016-06-25 20:04:06 +01:00
g = u . substring ( index + 1 );
2016-06-17 15:42:47 +01:00
u = u . substring ( 0 , index );
2015-12-19 18:53:33 +02:00
}
2017-08-18 10:53:57 +02:00
_url = urlDecode ( u );
2016-06-25 20:04:06 +01:00
_addGetParams ( g );
2015-12-19 18:53:33 +02:00
2016-06-29 16:20:03 +03:00
if ( ! _temp . startsWith ( "HTTP/1.0" ))
2016-01-27 18:46:49 +02:00
_version = 1 ;
2016-06-25 20:04:06 +01:00
2015-12-19 18:53:33 +02:00
_temp = String ();
return true ;
}
2017-08-18 17:52:21 +03:00
bool strContains ( String src , String find , bool mindcase = true ) {
int pos = 0 , i = 0 ;
const int slen = src . length ();
const int flen = find . length ();
if ( slen < flen ) return false ;
while ( pos <= ( slen - flen )) {
for ( i = 0 ; i < flen ; i ++ ) {
if ( mindcase ) {
if ( src [ pos + i ] != find [ i ]) i = flen + 1 ; // no match
} else if ( tolower ( src [ pos + i ]) != tolower ( find [ i ])) i = flen + 1 ; // no match
}
if ( i == flen ) return true ;
pos ++ ;
}
return false ;
}
2015-12-19 18:53:33 +02:00
bool AsyncWebServerRequest :: _parseReqHeader (){
2016-06-17 15:42:47 +01:00
int index = _temp . indexOf ( ':' );
if ( index ){
String name = _temp . substring ( 0 , index );
String value = _temp . substring ( index + 2 );
2016-09-02 13:52:32 +03:00
if ( name . equalsIgnoreCase ( "Host" )){
2016-06-17 15:42:47 +01:00
_host = value ;
2016-09-02 13:52:32 +03:00
} else if ( name . equalsIgnoreCase ( "Content-Type" )){
2016-06-17 15:42:47 +01:00
if ( value . startsWith ( "multipart/" )){
_boundary = value . substring ( value . indexOf ( '=' ) + 1 );
2017-08-17 19:17:21 +02:00
_boundary . replace ( " \" " , "" );
2016-06-17 15:42:47 +01:00
_contentType = value . substring ( 0 , value . indexOf ( ';' ));
2015-12-19 18:53:33 +02:00
_isMultipart = true ;
} else {
2016-06-17 15:42:47 +01:00
_contentType = value ;
2015-12-19 18:53:33 +02:00
}
2016-09-02 13:52:32 +03:00
} else if ( name . equalsIgnoreCase ( "Content-Length" )){
2016-06-17 15:42:47 +01:00
_contentLength = atoi ( value . c_str ());
2016-09-02 13:52:32 +03:00
} else if ( name . equalsIgnoreCase ( "Expect" ) && value == "100-continue" ){
2015-12-19 18:53:33 +02:00
_expectingContinue = true ;
2016-09-02 13:52:32 +03:00
} else if ( name . equalsIgnoreCase ( "Authorization" )){
if ( value . length () > 5 && value . substring ( 0 , 5 ). equalsIgnoreCase ( "Basic" )){
2016-06-17 15:42:47 +01:00
_authorization = value . substring ( 6 );
2016-09-02 13:52:32 +03:00
} else if ( value . length () > 6 && value . substring ( 0 , 6 ). equalsIgnoreCase ( "Digest" )){
2016-06-29 16:20:03 +03:00
_isDigest = true ;
_authorization = value . substring ( 7 );
2015-12-19 18:53:33 +02:00
}
} else {
2017-08-18 17:52:21 +03:00
if ( name . equalsIgnoreCase ( "Upgrade" ) && value . equalsIgnoreCase ( "websocket" )){
// WebSocket request can be uniquely identified by header: [Upgrade: websocket]
_reqconntype = RCT_WS ;
} else {
if ( name . equalsIgnoreCase ( "Accept" ) && strContains ( value , "text/event-stream" , false )){
// WebEvent request can be uniquely identified by header: [Accept: text/event-stream]
_reqconntype = RCT_EVENT ;
}
2016-06-17 15:42:47 +01:00
}
2015-12-19 18:53:33 +02:00
}
2017-08-18 17:52:21 +03:00
_headers . add ( new AsyncWebHeader ( name , value ));
2015-12-19 18:53:33 +02:00
}
_temp = String ();
return true ;
}
void AsyncWebServerRequest :: _parsePlainPostChar ( uint8_t data ){
2016-01-21 19:28:29 +02:00
if ( data && ( char ) data != '&' )
2015-12-19 18:53:33 +02:00
_temp += ( char ) data ;
2016-01-21 19:28:29 +02:00
if ( ! data || ( char ) data == '&' || _parsedLength == _contentLength ){
String name = "body" ;
String value = _temp ;
2016-01-21 19:32:40 +02:00
if ( ! _temp . startsWith ( "{" ) && ! _temp . startsWith ( "[" ) && _temp . indexOf ( '=' ) > 0 ){
2015-12-19 18:53:33 +02:00
name = _temp . substring ( 0 , _temp . indexOf ( '=' ));
value = _temp . substring ( _temp . indexOf ( '=' ) + 1 );
}
2017-08-18 10:53:57 +02:00
_addParam ( new AsyncWebParameter ( urlDecode ( name ), urlDecode ( value ), true ));
2015-12-19 18:53:33 +02:00
_temp = String ();
}
}
2016-02-09 02:32:14 +02:00
void AsyncWebServerRequest :: _handleUploadByte ( uint8_t data , bool last ){
_itemBuffer [ _itemBufferIndex ++ ] = data ;
2016-05-13 00:01:42 +03:00
2016-05-13 00:19:50 +03:00
if ( last || _itemBufferIndex == 1460 ){
2016-06-29 16:20:03 +03:00
//check if authenticated before calling the upload
2016-02-09 02:32:14 +02:00
if ( _handler )
_handler -> handleUpload ( this , _itemFilename , _itemSize - _itemBufferIndex , _itemBuffer , _itemBufferIndex , false );
_itemBufferIndex = 0 ;
}
}
2015-12-19 18:53:33 +02: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-22 01:41:57 +02:00
2015-12-19 18:53:33 +02:00
if ( ! _parsedLength ){
_multiParseState = EXPECT_BOUNDARY ;
_temp = String ();
_itemName = String ();
_itemFilename = String ();
_itemType = String ();
}
2016-05-13 00:01:42 +03:00
if ( _multiParseState == WAIT_FOR_RETURN1 ){
if ( data != '\r' ){
itemWriteByte ( data );
} else {
_multiParseState = EXPECT_FEED1 ;
}
} else if ( _multiParseState == EXPECT_BOUNDARY ){
2015-12-19 18:53:33 +02: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 23:30:14 +03:00
if ( _temp . length () > 12 && _temp . substring ( 0 , 12 ). equalsIgnoreCase ( "Content-Type" )){
2015-12-19 18:53:33 +02:00
_itemType = _temp . substring ( 14 );
_itemIsFile = true ;
2016-09-03 23:30:14 +03:00
} else if ( _temp . length () > 19 && _temp . substring ( 0 , 19 ). equalsIgnoreCase ( "Content-Disposition" )){
2015-12-19 18:53:33 +02: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-22 01:41:57 +02:00
free ( _itemBuffer );
_itemBuffer = ( uint8_t * ) malloc ( 1460 );
2016-05-13 00:01:42 +03:00
if ( _itemBuffer == NULL ){
_multiParseState = PARSE_ERROR ;
return ;
}
2015-12-19 18:53:33 +02:00
_itemBufferIndex = 0 ;
}
}
}
} else if ( _multiParseState == EXPECT_FEED1 ){
if ( data != '\n' ){
_multiParseState = WAIT_FOR_RETURN1 ;
2016-05-20 00:55:19 +03:00
itemWriteByte ( '\r' ); _parseMultipartPostByte ( data , last );
2015-12-19 18:53:33 +02:00
} else {
_multiParseState = EXPECT_DASH1 ;
}
} else if ( _multiParseState == EXPECT_DASH1 ){
if ( data != '-' ){
_multiParseState = WAIT_FOR_RETURN1 ;
2016-05-20 00:55:19 +03:00
itemWriteByte ( '\r' ); itemWriteByte ( '\n' ); _parseMultipartPostByte ( data , last );
2015-12-19 18:53:33 +02:00
} else {
_multiParseState = EXPECT_DASH2 ;
}
} else if ( _multiParseState == EXPECT_DASH2 ){
if ( data != '-' ){
_multiParseState = WAIT_FOR_RETURN1 ;
2016-05-20 00:55:19 +03:00
itemWriteByte ( '\r' ); itemWriteByte ( '\n' ); itemWriteByte ( '-' ); _parseMultipartPostByte ( data , last );
2015-12-19 18:53:33 +02: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-20 00:55:19 +03:00
_parseMultipartPostByte ( data , last );
2015-12-19 18:53:33 +02: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 16:20:03 +03:00
//check if authenticated before calling the upload
2015-12-19 18:53:33 +02:00
if ( _handler ) _handler -> handleUpload ( this , _itemFilename , _itemSize - _itemBufferIndex , _itemBuffer , _itemBufferIndex , true );
_itemBufferIndex = 0 ;
_addParam ( new AsyncWebParameter ( _itemName , _itemFilename , true , true , _itemSize ));
}
2015-12-22 01:41:57 +02:00
free ( _itemBuffer );
2016-11-29 22:12:52 +01:00
_itemBuffer = NULL ;
2015-12-19 18:53:33 +02:00
}
} else {
_boundaryPosition ++ ;
}
} else if ( _multiParseState == DASH3_OR_RETURN2 ){
2016-01-21 16:39:12 +02:00
if ( data == '-' && ( _contentLength - _parsedLength - 4 ) != 0 ){
2017-09-07 22:01:58 +03:00
//os_printf("ERROR: The parser got to the end of the POST but is expecting %u bytes more!\nDrop an issue so we can have more info on the matter!\n", _contentLength - _parsedLength - 4);
2016-01-21 16:39:12 +02:00
_contentLength = _parsedLength + 4 ; //lets close the request gracefully
}
2015-12-19 18:53:33 +02: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-20 00:55:19 +03:00
_parseMultipartPostByte ( data , last );
2015-12-19 18:53:33 +02: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-20 00:55:19 +03:00
itemWriteByte ( '\r' ); _parseMultipartPostByte ( data , last );
2015-12-19 18:53:33 +02:00
}
}
}
2016-02-09 02:32:14 +02: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 ;
}
if ( _parseState == PARSE_REQ_HEADERS ){
if ( ! _temp . length ()){
//end of headers
2017-08-18 17:52:21 +03:00
_server -> _rewriteRequest ( this );
_server -> _attachHandler ( this );
_removeNotInterestingHeaders ();
2016-02-09 02:32:14 +02:00
if ( _expectingContinue ){
const char * response = "HTTP/1.1 100 Continue \r\n\r\n " ;
_client -> write ( response , os_strlen ( response ));
}
2016-06-29 16:20:03 +03:00
//check handler for authentication
2016-02-09 02:32:14 +02:00
if ( _contentLength ){
_parseState = PARSE_REQ_BODY ;
} else {
_parseState = PARSE_REQ_END ;
if ( _handler ) _handler -> handleRequest ( this );
else send ( 501 );
}
} else _parseReqHeader ();
}
}
2016-11-27 17:42:09 +02:00
size_t AsyncWebServerRequest :: headers () const {
return _headers . length ();
2016-02-09 02:32:14 +02:00
}
2015-12-19 18:53:33 +02:00
2016-11-27 17:42:09 +02:00
bool AsyncWebServerRequest :: hasHeader ( const String & name ) const {
for ( const auto & h : _headers ){
if ( h -> name (). equalsIgnoreCase ( name )){
2016-02-09 02:32:14 +02:00
return true ;
2016-11-27 17:42:09 +02:00
}
2016-02-09 02:32:14 +02:00
}
return false ;
}
2017-03-05 18:06:57 +00: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 17:42:09 +02:00
AsyncWebHeader * AsyncWebServerRequest :: getHeader ( const String & name ) const {
for ( const auto & h : _headers ){
if ( h -> name (). equalsIgnoreCase ( name )){
2016-02-09 02:32:14 +02:00
return h ;
2016-11-27 17:42:09 +02:00
}
2016-02-09 02:32:14 +02:00
}
2016-11-27 17:42:09 +02:00
return nullptr ;
2016-02-09 02:32:14 +02:00
}
2017-03-05 18:06:57 +00: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 17:42:09 +02:00
AsyncWebHeader * AsyncWebServerRequest :: getHeader ( size_t num ) const {
auto header = _headers . nth ( num );
return header ? * header : nullptr ;
2016-02-09 02:32:14 +02:00
}
2016-11-27 17:42:09 +02:00
size_t AsyncWebServerRequest :: params () const {
return _params . length ();
2016-02-09 02:32:14 +02:00
}
2016-11-27 17:42:09 +02: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-09 02:32:14 +02:00
return true ;
2016-11-27 17:42:09 +02:00
}
2016-02-09 02:32:14 +02:00
}
return false ;
}
2017-03-05 18:06:57 +00: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 17:42:09 +02: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-09 02:32:14 +02:00
}
2016-11-27 17:42:09 +02:00
return nullptr ;
2016-02-09 02:32:14 +02:00
}
2017-03-05 18:06:57 +00: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 17:42:09 +02:00
AsyncWebParameter * AsyncWebServerRequest :: getParam ( size_t num ) const {
auto param = _params . nth ( num );
return param ? * param : nullptr ;
2016-02-09 02:32:14 +02:00
}
2016-11-27 17:42:09 +02:00
void AsyncWebServerRequest :: addInterestingHeader ( const String & name ){
if ( ! _interestingHeaders . containsIgnoreCase ( name ))
_interestingHeaders . add ( name );
2016-02-09 02:32:14 +02:00
}
void AsyncWebServerRequest :: send ( AsyncWebServerResponse * response ){
_response = response ;
2016-04-08 17:43:16 +03:00
if ( _response == NULL ){
_client -> close ( true );
_onDisconnect ();
return ;
}
2016-04-11 21:42:37 +03:00
if ( ! _response -> _sourceValid ()){
delete response ;
_response = NULL ;
2016-04-08 17:43:16 +03:00
send ( 500 );
2016-04-11 21:42:37 +03:00
}
2017-03-05 13:15:25 -05:00
else {
_client -> setRxTimeout ( 0 );
2016-04-08 17:43:16 +03:00
_response -> _respond ( this );
2017-03-05 13:15:25 -05:00
}
2016-02-09 02:32:14 +02:00
}
2016-11-27 17:42:09 +02:00
AsyncWebServerResponse * AsyncWebServerRequest :: beginResponse ( int code , const String & contentType , const String & content ){
2016-02-09 02:32:14 +02:00
return new AsyncBasicResponse ( code , contentType , content );
}
2017-08-18 17:59:06 +03:00
AsyncWebServerResponse * AsyncWebServerRequest :: beginResponse ( FS & fs , const String & path , const String & contentType , bool download , AwsTemplateProcessor callback ){
2016-02-09 02:32:14 +02:00
if ( fs . exists ( path ) || ( ! download && fs . exists ( path + ".gz" )))
2017-08-18 17:59:06 +03:00
return new AsyncFileResponse ( fs , path , contentType , download , callback );
2016-02-09 02:32:14 +02:00
return NULL ;
}
2017-08-18 17:59:06 +03:00
AsyncWebServerResponse * AsyncWebServerRequest :: beginResponse ( File content , const String & path , const String & contentType , bool download , AwsTemplateProcessor callback ){
2016-06-17 01:43:59 +03:00
if ( content == true )
2017-08-18 17:59:06 +03:00
return new AsyncFileResponse ( content , path , contentType , download , callback );
2016-06-17 01:43:59 +03:00
return NULL ;
}
2017-08-18 17:59:06 +03:00
AsyncWebServerResponse * AsyncWebServerRequest :: beginResponse ( Stream & stream , const String & contentType , size_t len , AwsTemplateProcessor callback ){
return new AsyncStreamResponse ( stream , contentType , len , callback );
2016-02-09 02:32:14 +02:00
}
2017-08-18 17:59:06 +03:00
AsyncWebServerResponse * AsyncWebServerRequest :: beginResponse ( const String & contentType , size_t len , AwsResponseFiller callback , AwsTemplateProcessor templateCallback ){
return new AsyncCallbackResponse ( contentType , len , callback , templateCallback );
2016-02-09 02:32:14 +02:00
}
2017-08-18 17:59:06 +03:00
AsyncWebServerResponse * AsyncWebServerRequest :: beginChunkedResponse ( const String & contentType , AwsResponseFiller callback , AwsTemplateProcessor templateCallback ){
2016-02-09 02:32:14 +02:00
if ( _version )
2017-08-18 17:59:06 +03:00
return new AsyncChunkedResponse ( contentType , callback , templateCallback );
return new AsyncCallbackResponse ( contentType , 0 , callback , templateCallback );
2016-02-09 02:32:14 +02:00
}
2016-11-27 17:42:09 +02:00
AsyncResponseStream * AsyncWebServerRequest :: beginResponseStream ( const String & contentType , size_t bufferSize ){
2016-02-09 02:32:14 +02:00
return new AsyncResponseStream ( contentType , bufferSize );
}
2017-08-18 17:59:06 +03:00
AsyncWebServerResponse * AsyncWebServerRequest :: beginResponse_P ( int code , const String & contentType , const uint8_t * content , size_t len , AwsTemplateProcessor callback ){
return new AsyncProgmemResponse ( code , contentType , content , len , callback );
2016-07-21 12:25:20 +03:00
}
2017-08-18 17:59:06 +03:00
AsyncWebServerResponse * AsyncWebServerRequest :: beginResponse_P ( int code , const String & contentType , PGM_P content , AwsTemplateProcessor callback ){
return beginResponse_P ( code , contentType , ( const uint8_t * ) content , strlen_P ( content ), callback );
2016-07-21 12:25:20 +03:00
}
2016-11-27 17:42:09 +02:00
void AsyncWebServerRequest :: send ( int code , const String & contentType , const String & content ){
2016-02-09 02:32:14 +02:00
send ( beginResponse ( code , contentType , content ));
}
2017-08-18 17:59:06 +03:00
void AsyncWebServerRequest :: send ( FS & fs , const String & path , const String & contentType , bool download , AwsTemplateProcessor callback ){
2016-02-09 02:32:14 +02:00
if ( fs . exists ( path ) || ( ! download && fs . exists ( path + ".gz" ))){
2017-08-18 17:59:06 +03:00
send ( beginResponse ( fs , path , contentType , download , callback ));
2016-02-09 02:32:14 +02:00
} else send ( 404 );
}
2017-08-18 17:59:06 +03:00
void AsyncWebServerRequest :: send ( File content , const String & path , const String & contentType , bool download , AwsTemplateProcessor callback ){
2016-06-17 01:43:59 +03:00
if ( content == true ){
2017-08-18 17:59:06 +03:00
send ( beginResponse ( content , path , contentType , download , callback ));
2016-06-17 01:43:59 +03:00
} else send ( 404 );
}
2017-08-18 17:59:06 +03:00
void AsyncWebServerRequest :: send ( Stream & stream , const String & contentType , size_t len , AwsTemplateProcessor callback ){
send ( beginResponse ( stream , contentType , len , callback ));
2016-02-09 02:32:14 +02:00
}
2017-08-18 17:59:06 +03:00
void AsyncWebServerRequest :: send ( const String & contentType , size_t len , AwsResponseFiller callback , AwsTemplateProcessor templateCallback ){
send ( beginResponse ( contentType , len , callback , templateCallback ));
2016-02-09 02:32:14 +02:00
}
2017-08-18 17:59:06 +03:00
void AsyncWebServerRequest :: sendChunked ( const String & contentType , AwsResponseFiller callback , AwsTemplateProcessor templateCallback ){
send ( beginChunkedResponse ( contentType , callback , templateCallback ));
2016-02-09 02:32:14 +02:00
}
2017-08-18 17:59:06 +03:00
void AsyncWebServerRequest :: send_P ( int code , const String & contentType , const uint8_t * content , size_t len , AwsTemplateProcessor callback ){
send ( beginResponse_P ( code , contentType , content , len , callback ));
2016-07-21 12:25:20 +03:00
}
2017-08-18 17:59:06 +03:00
void AsyncWebServerRequest :: send_P ( int code , const String & contentType , PGM_P content , AwsTemplateProcessor callback ){
send ( beginResponse_P ( code , contentType , content , callback ));
2016-07-21 12:25:20 +03:00
}
2016-11-27 17:42:09 +02:00
void AsyncWebServerRequest :: redirect ( const String & url ){
2016-06-26 16:20:21 +03:00
AsyncWebServerResponse * response = beginResponse ( 302 );
response -> addHeader ( "Location" , url );
send ( response );
}
2016-06-29 16:20:03 +03:00
bool AsyncWebServerRequest :: authenticate ( const char * username , const char * password , const char * realm , bool passwordIsHash ){
2016-02-09 02:32:14 +02:00
if ( _authorization . length ()){
2016-06-29 16:20:03 +03: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-09 02:32:14 +02:00
}
return false ;
}
bool AsyncWebServerRequest :: authenticate ( const char * hash ){
2016-06-29 16:20:03 +03: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-09 02:32:14 +02:00
}
2016-06-29 16:20:03 +03:00
void AsyncWebServerRequest :: requestAuthentication ( const char * realm , bool isDigest ){
2016-02-09 02:32:14 +02:00
AsyncWebServerResponse * r = beginResponse ( 401 );
2016-06-29 16:20:03 +03: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-09 02:32:14 +02:00
send ( r );
}
2016-11-27 17:42:09 +02:00
bool AsyncWebServerRequest :: hasArg ( const char * name ) const {
for ( const auto & arg : _params ){
if ( arg -> name () == name ){
2016-02-09 02:32:14 +02:00
return true ;
2016-11-27 17:42:09 +02:00
}
2016-02-09 02:32:14 +02:00
}
return false ;
}
2017-03-05 18:06:57 +00: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 17:42:09 +02:00
const String & AsyncWebServerRequest :: arg ( const String & name ) const {
for ( const auto & arg : _params ){
if ( arg -> name () == name ){
return arg -> value ();
}
2016-02-09 02:32:14 +02:00
}
2016-11-27 17:42:09 +02:00
return SharedEmptyString ;
2016-02-09 02:32:14 +02:00
}
2017-03-05 18:06:57 +00: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 17:42:09 +02:00
const String & AsyncWebServerRequest :: arg ( size_t i ) const {
2016-02-09 02:32:14 +02:00
return getParam ( i ) -> value ();
}
2016-11-27 17:42:09 +02:00
const String & AsyncWebServerRequest :: argName ( size_t i ) const {
2016-02-09 02:32:14 +02:00
return getParam ( i ) -> name ();
}
2016-11-27 17:42:09 +02:00
const String & AsyncWebServerRequest :: header ( const char * name ) const {
2016-02-09 02:32:14 +02:00
AsyncWebHeader * h = getHeader ( String ( name ));
2016-11-27 17:42:09 +02:00
return h ? h -> value () : SharedEmptyString ;
2016-02-09 02:32:14 +02:00
}
2017-03-05 18:06:57 +00: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 17:42:09 +02:00
const String & AsyncWebServerRequest :: header ( size_t i ) const {
2016-02-09 02:32:14 +02:00
AsyncWebHeader * h = getHeader ( i );
2016-11-27 17:42:09 +02:00
return h ? h -> value () : SharedEmptyString ;
2016-02-09 02:32:14 +02:00
}
2016-11-27 17:42:09 +02:00
const String & AsyncWebServerRequest :: headerName ( size_t i ) const {
2016-02-09 02:32:14 +02:00
AsyncWebHeader * h = getHeader ( i );
2016-11-27 17:42:09 +02:00
return h ? h -> name () : SharedEmptyString ;
2016-02-09 02:32:14 +02:00
}
2016-11-27 17:42:09 +02:00
String AsyncWebServerRequest :: urlDecode ( const String & text ) const {
2016-02-09 02:32:14 +02:00
char temp [] = "0x00" ;
unsigned int len = text . length ();
unsigned int i = 0 ;
2016-06-17 15:42:47 +01:00
String decoded = String ();
decoded . reserve ( len ); // Allocate the string internal buffer - never longer from source text
2016-02-09 02:32:14 +02: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 15:42:47 +01:00
} else if ( encodedChar == '+' ) {
decodedChar = ' ' ;
2016-02-09 02:32:14 +02:00
} else {
2016-06-17 15:42:47 +01:00
decodedChar = encodedChar ; // normal ascii char
2016-02-09 02:32:14 +02:00
}
2016-06-17 15:42:47 +01:00
decoded . concat ( decodedChar );
2016-02-09 02:32:14 +02:00
}
return decoded ;
}
2016-11-27 17:42:09 +02:00
const char * AsyncWebServerRequest :: methodToString () const {
2016-02-09 02:32:14 +02:00
if ( _method == HTTP_ANY ) return "ANY" ;
2016-08-19 22:21:08 +03: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-09 02:32:14 +02:00
return "UNKNOWN" ;
}
2017-08-18 17:52:21 +03:00
const char * AsyncWebServerRequest :: requestedConnTypeToString () const {
switch ( _reqconntype ) {
case RCT_NOT_USED : return "RCT_NOT_USED" ;
case RCT_DEFAULT : return "RCT_DEFAULT" ;
case RCT_HTTP : return "RCT_HTTP" ;
case RCT_WS : return "RCT_WS" ;
case RCT_EVENT : return "RCT_EVENT" ;
default : return "ERROR" ;
}
}
bool AsyncWebServerRequest :: isExpectedRequestedConnType ( RequestedConnectionType erct1 , RequestedConnectionType erct2 , RequestedConnectionType erct3 ) {
bool res = false ;
if (( erct1 != RCT_NOT_USED ) && ( erct1 == _reqconntype )) res = true ;
if (( erct2 != RCT_NOT_USED ) && ( erct2 == _reqconntype )) res = true ;
if (( erct3 != RCT_NOT_USED ) && ( erct3 == _reqconntype )) res = true ;
return res ;
}