This commit solves issues 172 and 198 (#207)
* This commit solves issues 172 and 198 * This commit solves issues 172 and 198
This commit is contained in:
parent
05ed854d7b
commit
77a520ba24
|
@ -307,7 +307,7 @@ size_t AsyncEventSource::count() const {
|
|||
}
|
||||
|
||||
bool AsyncEventSource::canHandle(AsyncWebServerRequest *request){
|
||||
if(request->method() != HTTP_GET || !request->url().equals(_url))
|
||||
if(request->method() != HTTP_GET || !request->url().equals(_url) || !request->isExpectedRequestedConnType(RCT_EVENT))
|
||||
return false;
|
||||
request->addInterestingHeader("Last-Event-ID");
|
||||
return true;
|
||||
|
|
|
@ -40,6 +40,7 @@ void SHA1Final(unsigned char digest[20], SHA1_CTX* context);
|
|||
#include <Hash.h>
|
||||
#endif
|
||||
|
||||
#define MAX_PRINTF_LEN 64
|
||||
|
||||
size_t webSocketSendFrameWindow(AsyncClient *client){
|
||||
if(!client->canSend())
|
||||
|
@ -645,16 +646,18 @@ void AsyncWebSocketClient::_onData(void *buf, size_t plen){
|
|||
size_t AsyncWebSocketClient::printf(const char *format, ...) {
|
||||
va_list arg;
|
||||
va_start(arg, format);
|
||||
char* temp = new char[64];
|
||||
char* temp = new char[MAX_PRINTF_LEN];
|
||||
if(!temp){
|
||||
return 0;
|
||||
}
|
||||
char* buffer = temp;
|
||||
size_t len = vsnprintf(temp, 64, format, arg);
|
||||
size_t len = vsnprintf(temp, MAX_PRINTF_LEN, format, arg);
|
||||
va_end(arg);
|
||||
if (len > 63) {
|
||||
|
||||
if (len > (MAX_PRINTF_LEN - 1)) {
|
||||
buffer = new char[len + 1];
|
||||
if (!buffer) {
|
||||
delete[] temp;
|
||||
return 0;
|
||||
}
|
||||
va_start(arg, format);
|
||||
|
@ -672,16 +675,18 @@ size_t AsyncWebSocketClient::printf(const char *format, ...) {
|
|||
size_t AsyncWebSocketClient::printf_P(PGM_P formatP, ...) {
|
||||
va_list arg;
|
||||
va_start(arg, formatP);
|
||||
char* temp = new char[64];
|
||||
char* temp = new char[MAX_PRINTF_LEN];
|
||||
if(!temp){
|
||||
return 0;
|
||||
}
|
||||
char* buffer = temp;
|
||||
size_t len = vsnprintf_P(temp, 64, formatP, arg);
|
||||
size_t len = vsnprintf_P(temp, MAX_PRINTF_LEN, formatP, arg);
|
||||
va_end(arg);
|
||||
if (len > 63) {
|
||||
|
||||
if (len > (MAX_PRINTF_LEN - 1)) {
|
||||
buffer = new char[len + 1];
|
||||
if (!buffer) {
|
||||
delete[] temp;
|
||||
return 0;
|
||||
}
|
||||
va_start(arg, formatP);
|
||||
|
@ -928,10 +933,14 @@ size_t AsyncWebSocket::printf(uint32_t id, const char *format, ...){
|
|||
|
||||
size_t AsyncWebSocket::printfAll(const char *format, ...) {
|
||||
va_list arg;
|
||||
va_start(arg, format);
|
||||
char* temp = new char[MAX_PRINTF_LEN];
|
||||
if(!temp){
|
||||
return 0;
|
||||
size_t len = vsnprintf(nullptr, 0, format, arg);
|
||||
}
|
||||
va_start(arg, format);
|
||||
size_t len = vsnprintf(temp, MAX_PRINTF_LEN, format, arg);
|
||||
va_end(arg);
|
||||
delete[] temp;
|
||||
|
||||
AsyncWebSocketMessageBuffer * buffer = makeBuffer(len + 1);
|
||||
if (!buffer) {
|
||||
|
@ -960,17 +969,24 @@ size_t AsyncWebSocket::printf_P(uint32_t id, PGM_P formatP, ...){
|
|||
|
||||
size_t AsyncWebSocket::printfAll_P(PGM_P formatP, ...) {
|
||||
va_list arg;
|
||||
char* temp = new char[MAX_PRINTF_LEN];
|
||||
if(!temp){
|
||||
return 0;
|
||||
}
|
||||
va_start(arg, formatP);
|
||||
size_t len = vsnprintf_P(nullptr, 0, formatP, arg);
|
||||
size_t len = vsnprintf_P(temp, MAX_PRINTF_LEN, formatP, arg);
|
||||
va_end(arg);
|
||||
delete[] temp;
|
||||
|
||||
AsyncWebSocketMessageBuffer * buffer = makeBuffer(len + 1);
|
||||
if (!buffer) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
va_start(arg, formatP);
|
||||
vsnprintf_P( (char *)buffer->get(), len + 1, formatP, arg);
|
||||
vsnprintf_P((char *)buffer->get(), len + 1, formatP, arg);
|
||||
va_end(arg);
|
||||
|
||||
textAll(buffer);
|
||||
return len;
|
||||
}
|
||||
|
@ -1059,7 +1075,7 @@ bool AsyncWebSocket::canHandle(AsyncWebServerRequest *request){
|
|||
if(!_enabled)
|
||||
return false;
|
||||
|
||||
if(request->method() != HTTP_GET || !request->url().equals(_url))
|
||||
if(request->method() != HTTP_GET || !request->url().equals(_url) || !request->isExpectedRequestedConnType(RCT_WS))
|
||||
return false;
|
||||
|
||||
request->addInterestingHeader(WS_STR_CONNECTION);
|
||||
|
|
|
@ -113,6 +113,8 @@ class AsyncWebHeader {
|
|||
* REQUEST :: Each incoming Client is wrapped inside a Request and both live together until disconnect
|
||||
* */
|
||||
|
||||
typedef enum { RCT_NOT_USED = -1, RCT_DEFAULT = 0, RCT_HTTP, RCT_WS, RCT_EVENT, RCT_MAX } RequestedConnectionType;
|
||||
|
||||
typedef std::function<size_t(uint8_t*, size_t, size_t)> AwsResponseFiller;
|
||||
|
||||
class AsyncWebServerRequest {
|
||||
|
@ -136,6 +138,8 @@ class AsyncWebServerRequest {
|
|||
String _contentType;
|
||||
String _boundary;
|
||||
String _authorization;
|
||||
RequestedConnectionType _reqconntype;
|
||||
void _removeNotInterestingHeaders();
|
||||
bool _isDigest;
|
||||
bool _isMultipart;
|
||||
bool _isPlainPost;
|
||||
|
@ -194,7 +198,9 @@ class AsyncWebServerRequest {
|
|||
size_t contentLength() const { return _contentLength; }
|
||||
bool multipart() const { return _isMultipart; }
|
||||
const char * methodToString() const;
|
||||
|
||||
const char * requestedConnTypeToString() const;
|
||||
RequestedConnectionType requestedConnType() const { return _reqconntype; }
|
||||
bool isExpectedRequestedConnType(RequestedConnectionType erct1, RequestedConnectionType erct2 = RCT_NOT_USED, RequestedConnectionType erct3 = RCT_NOT_USED);
|
||||
|
||||
//hash is the string representation of:
|
||||
// base64(user:pass) for basic or
|
||||
|
|
|
@ -81,10 +81,13 @@ AsyncStaticWebHandler& AsyncStaticWebHandler::setLastModified(){
|
|||
}
|
||||
#endif
|
||||
bool AsyncStaticWebHandler::canHandle(AsyncWebServerRequest *request){
|
||||
if (request->method() == HTTP_GET &&
|
||||
request->url().startsWith(_uri) &&
|
||||
_getFile(request)) {
|
||||
|
||||
if(request->method() != HTTP_GET
|
||||
|| !request->url().startsWith(_uri)
|
||||
|| !request->isExpectedRequestedConnType(RCT_DEFAULT, RCT_HTTP)
|
||||
){
|
||||
return false;
|
||||
}
|
||||
if (_getFile(request)) {
|
||||
// We interested in "If-Modified-Since" header to check if file was modified
|
||||
if (_last_modified.length())
|
||||
request->addInterestingHeader("If-Modified-Since");
|
||||
|
|
|
@ -46,6 +46,7 @@ AsyncWebServerRequest::AsyncWebServerRequest(AsyncWebServer* s, AsyncClient* c)
|
|||
, _contentType()
|
||||
, _boundary()
|
||||
, _authorization()
|
||||
, _reqconntype(RCT_HTTP)
|
||||
, _isDigest(false)
|
||||
, _isMultipart(false)
|
||||
, _isPlainPost(false)
|
||||
|
@ -96,13 +97,17 @@ AsyncWebServerRequest::~AsyncWebServerRequest(){
|
|||
}
|
||||
|
||||
void AsyncWebServerRequest::_onData(void *buf, size_t len){
|
||||
int i = 0;
|
||||
while (true) {
|
||||
|
||||
if(_parseState < PARSE_REQ_BODY){
|
||||
// Find new line in buf
|
||||
char *str = (char*)buf;
|
||||
size_t i = 0;
|
||||
for (; i < len; i++) if (str[i] == '\n') break;
|
||||
for (i = 0; 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;
|
||||
|
@ -152,7 +157,6 @@ void AsyncWebServerRequest::_onData(void *buf, size_t len){
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(_parsedLength == _contentLength){
|
||||
_parseState = PARSE_REQ_END;
|
||||
//check if authenticated before calling handleRequest and request auth instead
|
||||
|
@ -160,11 +164,19 @@ void AsyncWebServerRequest::_onData(void *buf, size_t len){
|
|||
else send(501);
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AsyncWebServerRequest::_onPoll(){
|
||||
//os_printf("p\n");
|
||||
if(_response != NULL && _client != NULL && _client->canSend() && !_response->_finished()){
|
||||
|
@ -257,6 +269,24 @@ bool AsyncWebServerRequest::_parseReqHead(){
|
|||
return true;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
bool AsyncWebServerRequest::_parseReqHeader(){
|
||||
int index = _temp.indexOf(':');
|
||||
if(index){
|
||||
|
@ -264,8 +294,6 @@ bool AsyncWebServerRequest::_parseReqHeader(){
|
|||
String value = _temp.substring(index + 2);
|
||||
if(name.equalsIgnoreCase("Host")){
|
||||
_host = value;
|
||||
_server->_rewriteRequest(this);
|
||||
_server->_attachHandler(this);
|
||||
} else if(name.equalsIgnoreCase("Content-Type")){
|
||||
if (value.startsWith("multipart/")){
|
||||
_boundary = value.substring(value.indexOf('=')+1);
|
||||
|
@ -287,11 +315,18 @@ bool AsyncWebServerRequest::_parseReqHeader(){
|
|||
_authorization = value.substring(7);
|
||||
}
|
||||
} else {
|
||||
if(_interestingHeaders.containsIgnoreCase(name) || _interestingHeaders.containsIgnoreCase("ANY")){
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
_headers.add(new AsyncWebHeader(name, value));
|
||||
}
|
||||
}
|
||||
}
|
||||
_temp = String();
|
||||
return true;
|
||||
}
|
||||
|
@ -511,6 +546,9 @@ void AsyncWebServerRequest::_parseLine(){
|
|||
if(_parseState == PARSE_REQ_HEADERS){
|
||||
if(!_temp.length()){
|
||||
//end of headers
|
||||
_server->_rewriteRequest(this);
|
||||
_server->_attachHandler(this);
|
||||
_removeNotInterestingHeaders();
|
||||
if(_expectingContinue){
|
||||
const char * response = "HTTP/1.1 100 Continue\r\n\r\n";
|
||||
_client->write(response, os_strlen(response));
|
||||
|
@ -924,3 +962,22 @@ const char * AsyncWebServerRequest::methodToString() const {
|
|||
else if(_method & HTTP_OPTIONS) return "OPTIONS";
|
||||
return "UNKNOWN";
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue