Added full HTTP cookie support to the WEBServer, did some cleanup and refactoring around the HTTP Header Parsing algorithm to ease the cookie parser implementation
This commit is contained in:
parent
bbebac6212
commit
0f68644064
@ -32,6 +32,7 @@ WEBClient::~WEBClient()
|
||||
void WEBClient::clearHttpRequestData()
|
||||
{
|
||||
free(_httpRequestData.httpResource);free(_httpRequestData.httpBody);
|
||||
_httpRequestData.cookies.dispose();
|
||||
_httpRequestData.getParams.dispose();
|
||||
_httpRequestData.postParams.dispose();
|
||||
}
|
||||
|
@ -20,17 +20,14 @@ class WEBServer : public TCPServer<T>, public HttpConstants
|
||||
PARSE_HTTP_VERSION,
|
||||
PARSE_HTTP_RESOURCE_QUERY,
|
||||
PARSE_HTTP_POST_DATA,
|
||||
PARSE_HTTP_HEADER_PARAMS
|
||||
PARSE_HTTP_HEADER_PARAMS,
|
||||
PARSE_HTTP_COOKIES
|
||||
};
|
||||
enum WEBClientState {ACCEPTED, PARSING, QUERY_PARSED, RESPONSE_SENT, DONE};
|
||||
|
||||
struct HttpCookie
|
||||
{
|
||||
DictionaryHelper::StringEntity value;
|
||||
DictionaryHelper::StringEntity domain;
|
||||
DictionaryHelper::StringEntity path;
|
||||
int32_t sameSite : 1, httpOnly : 1, maxAge : 30;
|
||||
//Need to add the expires field as well. Thinking about the best way of doing it.
|
||||
};
|
||||
|
||||
struct HttpRequestData
|
||||
@ -40,6 +37,7 @@ class WEBServer : public TCPServer<T>, public HttpConstants
|
||||
HttpMIMEType HMT;
|
||||
size_t contentLength;
|
||||
|
||||
Dictionary<HttpCookie> cookies;
|
||||
Dictionary<DictionaryHelper::StringEntity> getParams;
|
||||
Dictionary<DictionaryHelper::StringEntity> postParams;
|
||||
char *postParamsDataPointer; //Used in the postParams algorithm
|
||||
@ -100,9 +98,9 @@ class WEBServer : public TCPServer<T>, public HttpConstants
|
||||
* The addCookie method adds cookies to the cookie dictionary which will be used when calling the sendHTTPResponse method.
|
||||
* Once the cookies are sent, the dictionary will be emptied.
|
||||
**/
|
||||
boolean addCookies(const char *cookieName, const char *cookieValue, int32_t maxAge = -1, const char *cookiePath = nullptr, const char *cookieDomain = nullptr, boolean httpOnly = false, boolean sameSite = false)
|
||||
boolean addCookies(const char *cookieName, const char *cookieValue = nullptr, int32_t maxAge = -1, const char *cookiePath = nullptr, const char *cookieDomain = nullptr, boolean httpOnly = false, boolean sameSite = false)
|
||||
{
|
||||
return _setCookieDictionary.add(cookieName, new HttpCookie({cookieValue, cookieDomain, cookiePath, sameSite, httpOnly, maxAge}));
|
||||
return _setCookieDictionary.add(cookieName, new ServerHttpCookie({cookieValue, cookieDomain, cookiePath, sameSite, httpOnly, maxAge}));
|
||||
}
|
||||
|
||||
void clearCookies(void)
|
||||
@ -136,10 +134,26 @@ class WEBServer : public TCPServer<T>, public HttpConstants
|
||||
//We here send the user defined cookies :)
|
||||
for(unsigned int i(0); i < _setCookieDictionary.count(); i++)
|
||||
{
|
||||
//client
|
||||
ServerHttpCookie *pCookie = _setCookieDictionary.getAt(i);
|
||||
|
||||
if(pCookie)
|
||||
{
|
||||
client->printf_P(PSTR("\r\nSet-Cookie: %s=%s"), _setCookieDictionary.getParameter(i), pCookie->value.getString());
|
||||
if(pCookie->maxAge != -1)
|
||||
client->printf_P(PSTR("; Max-Age=%d"), pCookie->maxAge);
|
||||
if(pCookie->sameSite)
|
||||
client->printf_P(PSTR("; SameSite=Strict"));
|
||||
if(pCookie->domain.getString()[0] != '\0')
|
||||
client->printf_P(PSTR("; Domain=%s"), pCookie->domain.getString());
|
||||
if(pCookie->path.getString()[0] != '\0')
|
||||
client->printf_P(PSTR("; Path=%s"), pCookie->path.getString());
|
||||
if(pCookie->httpOnly)
|
||||
client->printf_P(PSTR("; HttpOnly"));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//We do not forget to clear them after
|
||||
//We do not forget to clear the cookie dictionary after
|
||||
clearCookies();
|
||||
|
||||
client->print("\r\n\r\n");
|
||||
@ -270,7 +284,7 @@ class WEBServer : public TCPServer<T>, public HttpConstants
|
||||
|
||||
if(client->_httpRequestData.HRM == HttpRequestMethod::UNDEFINED) //Error 400
|
||||
{
|
||||
sendInfoResponse(HTTP_CODE::HTTP_CODE_BAD_REQUEST, client, "The server could not understand the request due to invalid syntax");
|
||||
sendInfoResponse(HTTP_CODE::HTTP_CODE_BAD_REQUEST, client, PSTR("The server could not understand the request due to invalid syntax"));
|
||||
client->_clientState = TCPClient::ClientState::DISCARDED;
|
||||
break;
|
||||
}
|
||||
@ -284,7 +298,7 @@ class WEBServer : public TCPServer<T>, public HttpConstants
|
||||
}
|
||||
else
|
||||
{
|
||||
sendInfoResponse(HTTP_CODE::HTTP_CODE_BAD_REQUEST, client, "The server could not understand the request due to invalid syntax");
|
||||
sendInfoResponse(HTTP_CODE::HTTP_CODE_BAD_REQUEST, client, PSTR("The server could not understand the request due to invalid syntax"));
|
||||
client->_clientState = TCPClient::ClientState::DISCARDED;
|
||||
}
|
||||
}
|
||||
@ -322,7 +336,7 @@ class WEBServer : public TCPServer<T>, public HttpConstants
|
||||
#ifdef DEBUG_WEBS
|
||||
Serial.printf("Resource too long\nResource raw length is : %u (\\0 included)\nMax length is : %u (\\0 included)\nclient->_data : #%s#\n", rawLengthOfResource + 1, client->_httpRequestData.maxResourceBuffer, (char *)client->_data);
|
||||
#endif
|
||||
sendInfoResponse(HTTP_CODE::HTTP_CODE_URI_TOO_LONG, client, "Resource too long");
|
||||
sendInfoResponse(HTTP_CODE::HTTP_CODE_URI_TOO_LONG, client, PSTR("Resource too long"));
|
||||
client->_clientState = TCPClient::ClientState::DISCARDED;
|
||||
break;
|
||||
}
|
||||
@ -361,7 +375,7 @@ class WEBServer : public TCPServer<T>, public HttpConstants
|
||||
Serial.printf("Could not find ' ' or '?' delimiter\nclient->_data : #%s#\n",
|
||||
(char *)client->_data);
|
||||
#endif
|
||||
sendInfoResponse(HTTP_CODE::HTTP_CODE_URI_TOO_LONG, client, "Resource too long");
|
||||
sendInfoResponse(HTTP_CODE::HTTP_CODE_URI_TOO_LONG, client, PSTR("Resource too long"));
|
||||
client->_clientState = TCPClient::ClientState::DISCARDED;
|
||||
break;
|
||||
}
|
||||
@ -413,43 +427,63 @@ class WEBServer : public TCPServer<T>, public HttpConstants
|
||||
client->_httpParserState = HttpParserStatus::PARSE_HTTP_VERSION;
|
||||
}
|
||||
break;
|
||||
case HttpParserStatus::PARSE_HTTP_HEADER_PARAMS: //Here we parse the different header params until we arrive to \r\n\r\n
|
||||
//Here we parse the different header params until we arrive to \r\n\r\n
|
||||
//We also know that header params are of the form : Param1: value1\r\nParam2: value2\r\n etc
|
||||
//So we look for the delimitor which is ":"
|
||||
case HttpParserStatus::PARSE_HTTP_HEADER_PARAMS:
|
||||
{
|
||||
char *pDelimiter(strchr((char *)client->_data, ':'));
|
||||
char *endHeaderDelimiter(strstr((char *)client->_data, "\r\n"));
|
||||
|
||||
//If we found the delimiter, this means there is at least one parameter
|
||||
if(pDelimiter)
|
||||
{
|
||||
char *pEndLine = strstr((char *)client->_data, "\r\n");
|
||||
|
||||
if( pEndLine != NULL )
|
||||
{
|
||||
*pEndLine = '\0';
|
||||
|
||||
httpHeaderParamParser(client);
|
||||
|
||||
if(*(pEndLine+2) == '\r') //We got \r\n\r\n -> so we go to the post data section
|
||||
{
|
||||
if(client->_httpRequestData.contentLength) //If a body is expected
|
||||
client->_httpParserState = HttpParserStatus::PARSE_HTTP_POST_DATA;
|
||||
else //Else we are done
|
||||
client->_WEBClientState = WEBClientState::QUERY_PARSED;
|
||||
|
||||
client->freeDataBuffer((pEndLine - (char *)client->_data) +3); //client->_data must not be empty...
|
||||
break;
|
||||
}
|
||||
|
||||
//Before in the buffer : key1: value1\r\nkey2: value2
|
||||
//After in the buffer : key2: value2\r\n
|
||||
client->freeDataBuffer((pEndLine - (char *)client->_data) + 2);
|
||||
}
|
||||
else //Error : indeed, we should at least have : \r\n. We go to the next step anyway
|
||||
{
|
||||
*pDelimiter = '\0';
|
||||
httpHeaderParamParser(client);
|
||||
}
|
||||
//There is maybe not headers so we go to the http body part
|
||||
else if(endHeaderDelimiter)
|
||||
{
|
||||
if(client->_httpRequestData.contentLength) //If a body is expected
|
||||
client->_httpParserState = HttpParserStatus::PARSE_HTTP_POST_DATA;
|
||||
else //Else we are done
|
||||
client->_WEBClientState = WEBClientState::QUERY_PARSED;
|
||||
|
||||
client->freeDataBuffer((endHeaderDelimiter - (char *)client->_data) +1); //client->_data must not be empty so we keep the last \n...
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef DEBUG_WEBS
|
||||
Serial.println("Error, should have found \\r\\n\\r\\n");
|
||||
#endif
|
||||
|
||||
sendInfoResponse(HTTP_CODE::HTTP_CODE_BAD_REQUEST, client, PSTR("The server could not understand the request due to invalid syntax"));
|
||||
client->_clientState = TCPClient::ClientState::DISCARDED;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case HttpParserStatus::PARSE_HTTP_COOKIES:
|
||||
if(!httpCookiesParser(client))
|
||||
{
|
||||
#ifdef DEBUG_WEBS
|
||||
Serial.println("Cookies :");
|
||||
for(unsigned int i = 0; i < client->_httpRequestData.cookies.count(); i++)
|
||||
{
|
||||
Serial.printf("#%s# : #%s#\n", client->_httpRequestData.cookies.getParameter(i), client->_httpRequestData.cookies.getAt(i)->value.getString());
|
||||
}
|
||||
Serial.printf("phc client->_data : #%s#\n", client->_data);
|
||||
#endif
|
||||
//Once we are done parsing the cookies, we go back to the HTTP HEADER PARAMS PARSER as there may be still some more after the cookies ?
|
||||
client->_httpParserState = HttpParserStatus::PARSE_HTTP_HEADER_PARAMS;
|
||||
}
|
||||
break;
|
||||
case HttpParserStatus::PARSE_HTTP_POST_DATA:
|
||||
|
||||
|
||||
switch(client->_httpRequestData.HMT)
|
||||
{
|
||||
case APPLICATION_X_WWW_FORM_URLENCODED:
|
||||
#if 1//def DEBUG_WEBS
|
||||
#ifdef DEBUG_WEBS
|
||||
Serial.printf("Post data : APPLICATION_X_WWW_FORM_URLENCODED\nPost data : #%s#\n", client->_data);
|
||||
#endif
|
||||
|
||||
@ -457,11 +491,11 @@ class WEBServer : public TCPServer<T>, public HttpConstants
|
||||
if(!httpPostParamParser(client))
|
||||
{
|
||||
//Parsing done!
|
||||
#if 1//def DEBUG_WEBS
|
||||
#ifdef DEBUG_WEBS
|
||||
Serial.println("Post params :");
|
||||
for(unsigned int i = 0; i < client->_httpRequestData.postParams.count(); i++)
|
||||
{
|
||||
Serial.print(client->_httpRequestData.postParams.getParameter(i));Serial.print(" : ");Serial.println(client->_httpRequestData.postParams.getAt(i)->getString());
|
||||
Serial.printf("#%s# : #%s#\n", client->_httpRequestData.postParams.getParameter(i), client->_httpRequestData.postParams.getAt(i)->getString());
|
||||
}
|
||||
#endif
|
||||
client->_WEBClientState = WEBClientState::QUERY_PARSED;
|
||||
@ -486,79 +520,116 @@ class WEBServer : public TCPServer<T>, public HttpConstants
|
||||
*/
|
||||
void httpHeaderParamParser(T *client)
|
||||
{
|
||||
#ifdef DEBUG_WEBS
|
||||
Serial.printf("Header param : %s\n",(char *)client->_data);
|
||||
#endif
|
||||
char *pHeaderParam((char *)client->_data);
|
||||
char *pHeaderValue((char *)client->_data + strlen((char *)client->_data) + 2); //+2 is to discard the ": "
|
||||
char *pHeaderEndOfValue(strstr((char *)pHeaderValue, "\r\n"));
|
||||
|
||||
//Here we check if we have interesting params
|
||||
char *search = strstr((char *)client->_data, "t-Type: application/x-www-form-urlen");
|
||||
if(search != nullptr)
|
||||
if(pHeaderEndOfValue)
|
||||
{
|
||||
*pHeaderEndOfValue = '\0';
|
||||
|
||||
#ifdef DEBUG_WEBS
|
||||
Serial.printf("Header param->value : #%s# -> #%s#\n", pHeaderParam, pHeaderValue);
|
||||
#endif
|
||||
|
||||
char *searchParam(strstr(pHeaderParam, "t-Type"));
|
||||
char *searchValue(strstr(pHeaderValue, "ion/x-www-for"));
|
||||
|
||||
if(searchParam && searchValue)
|
||||
{
|
||||
client->_httpRequestData.HMT = APPLICATION_X_WWW_FORM_URLENCODED;
|
||||
client->freeDataBuffer((pHeaderEndOfValue - (char *)client->_data) + 2);
|
||||
#ifdef DEBUG_WEBS
|
||||
Serial.println("Content-Type is APPLICATION_X_WWW_FORM_URLENCODED");
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
if((searchParam = strstr(pHeaderParam, "ion")) && (searchValue = strstr(pHeaderValue, "keep-al")))
|
||||
{
|
||||
client->_keepAlive = true;
|
||||
client->freeDataBuffer((pHeaderEndOfValue - (char *)client->_data) + 2);
|
||||
#ifdef DEBUG_WEBS
|
||||
Serial.println("Connection: keep-alive");
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
if((searchParam = strstr(pHeaderParam, "ent-Len")))
|
||||
{
|
||||
char *check(nullptr);
|
||||
client->_httpRequestData.contentLength = strtoul(pHeaderValue, &check, 10);
|
||||
|
||||
if(*check != '\0') //Failed to parse the content length !
|
||||
{
|
||||
client->_httpRequestData.contentLength = 0;
|
||||
#ifdef DEBUG_WEBS
|
||||
Serial.println("Failed to parse Content-Length");
|
||||
#endif
|
||||
}
|
||||
#ifdef DEBUG_WEBS
|
||||
else
|
||||
{
|
||||
Serial.printf("Content-Length: %u\n", client->_httpRequestData.contentLength);
|
||||
}
|
||||
#endif
|
||||
|
||||
client->freeDataBuffer((pHeaderEndOfValue - (char *)client->_data) + 2);
|
||||
return;
|
||||
}
|
||||
|
||||
//Range part for file downloads and media playback
|
||||
if((searchParam = strstr(pHeaderParam, "nge")) && (searchValue = strstr(pHeaderValue, "ytes=")))
|
||||
{
|
||||
//We need to parse the range values
|
||||
if(fillRangeByteStruct(client, pHeaderValue))
|
||||
{
|
||||
#ifdef DEBUG_WEBS
|
||||
Serial.printf("Range (bytes) data : start -> %u ; end -> %u\n", client->_rangeData._rangeStart, client->_rangeData._rangeEnd);
|
||||
#endif
|
||||
}
|
||||
#ifdef DEBUG_WEBS
|
||||
else
|
||||
{
|
||||
Serial.printf("Range (bytes) data parse error : start -> %u ; end -> %u\n", client->_rangeData._rangeStart, client->_rangeData._rangeEnd);
|
||||
}
|
||||
#endif
|
||||
|
||||
client->freeDataBuffer((pHeaderEndOfValue - (char *)client->_data) + 2);
|
||||
return;
|
||||
}
|
||||
|
||||
//Here we check if there are some cookies to be parsed
|
||||
if((searchParam = strstr(pHeaderParam, "okie")))
|
||||
{
|
||||
client->_httpParserState = HttpParserStatus::PARSE_HTTP_COOKIES;
|
||||
client->freeDataBuffer(pHeaderValue - (char *)client->_data);
|
||||
return;
|
||||
}
|
||||
|
||||
//We still need to remove
|
||||
client->freeDataBuffer((pHeaderEndOfValue - (char *)client->_data) + 2);
|
||||
}
|
||||
//Error, we did not find the \r\n, maybe the parameter value is too long, error needs to be handled !
|
||||
else
|
||||
{
|
||||
#ifdef DEBUG_WEBS
|
||||
Serial.printf("Content-Type : APPLICATION_X_WWW_FORM_URLENCODED\n");
|
||||
Serial.println("Error : header value \\r\\n not found!");
|
||||
#endif
|
||||
client->_httpRequestData.HMT = APPLICATION_X_WWW_FORM_URLENCODED;
|
||||
return; //No need to look further
|
||||
}
|
||||
|
||||
search = strstr((char *)client->_data, "ion: keep-al");
|
||||
if(search != nullptr)
|
||||
{
|
||||
#ifdef DEBUG_WEBS
|
||||
Serial.printf("Connection : keep-alive\n");
|
||||
#endif
|
||||
client->_keepAlive = true;
|
||||
return; //No need to look further
|
||||
}
|
||||
|
||||
//Range part for file downloads and media playback
|
||||
search = strstr((char *)client->_data, "nge: bytes=");
|
||||
|
||||
if(search != nullptr)
|
||||
{
|
||||
//We parse the range byte data
|
||||
if(fillRangeByteStruct(client))
|
||||
{
|
||||
#ifdef DEBUG_WEBS
|
||||
Serial.printf("Range (bytes) data : start -> %u ; end -> %u\n", client->_rangeData._rangeStart, client->_rangeData._rangeEnd);
|
||||
#endif
|
||||
client->_rangeData._rangeRequest = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef DEBUG_WEBS
|
||||
Serial.printf("Range (bytes) data parse error : start -> %u ; end -> %u\n", client->_rangeData._rangeStart, client->_rangeData._rangeEnd);
|
||||
#endif
|
||||
}
|
||||
return; //No need to look further
|
||||
}
|
||||
|
||||
//Content-length header
|
||||
search = strstr((char *)client->_data, "ent-Length: ");
|
||||
if(search != nullptr)
|
||||
{
|
||||
if(!fillContentLength(client))
|
||||
{
|
||||
#if 1//def DEBUG_WEBS
|
||||
Serial.printf("Failed to parse content length\n");
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
#if 1//def DEBUG_WEBS
|
||||
Serial.printf("Parsed content length is :%u\n", client->_httpRequestData.contentLength);
|
||||
#endif
|
||||
}
|
||||
return; //No need to look further
|
||||
sendInfoResponse(HTTP_CODE::HTTP_CODE_BAD_REQUEST, client, PSTR("The server could not understand the request due to invalid syntax"));
|
||||
client->_clientState = TCPClient::ClientState::DISCARDED;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* This function fills the client's _rangeData struct with proper values
|
||||
*/
|
||||
bool fillRangeByteStruct(T *client)
|
||||
bool fillRangeByteStruct(T *client, char *rangeBytesData)
|
||||
{
|
||||
char *rangeStart = strchr((char *)client->_data, '='), *delimiter = strchr((char *)client->_data, '-'), *check(nullptr);
|
||||
if(!rangeBytesData)return false;
|
||||
|
||||
char *rangeStart = strchr(rangeBytesData, '='), *delimiter = strchr(rangeBytesData, '-'), *check(nullptr);
|
||||
|
||||
if(!rangeStart)return false;
|
||||
|
||||
@ -583,24 +654,14 @@ class WEBServer : public TCPServer<T>, public HttpConstants
|
||||
//We parse the 2nd part of the range byte
|
||||
client->_rangeData._rangeEnd = strtoull(rangeStart, &check, 10);
|
||||
if(*check != '\0')return false;
|
||||
|
||||
client->_rangeData._rangeRequest = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function fills the client's _httpRequestData.contentLength attribut
|
||||
*/
|
||||
bool fillContentLength(T *client)
|
||||
{
|
||||
char *start(strchr((char *)client->_data, ':')), *check(nullptr);
|
||||
if(!start)return false;
|
||||
start++;
|
||||
client->_httpRequestData.contentLength = strtoul(start, &check, 10);
|
||||
|
||||
if(*check != '\0')return false;
|
||||
return true;
|
||||
}
|
||||
/*
|
||||
* This function is here to parse resources query parameters
|
||||
* This function parses resources query parameters
|
||||
*/
|
||||
boolean httpRsrcParamParser(T *client)
|
||||
{
|
||||
@ -691,6 +752,46 @@ class WEBServer : public TCPServer<T>, public HttpConstants
|
||||
return true;
|
||||
}
|
||||
|
||||
boolean httpCookiesParser(T *client)
|
||||
{
|
||||
//He we have the the Cookie field value like : TestCookie=TestValue; TestCookie2=; TestCookie3=TestValue3
|
||||
//It is what we need to parse.
|
||||
char *endOfKey(strchr((char *)client->_data, '='));
|
||||
char *endOfValue(strchr((char *)client->_data, ';'));
|
||||
char *failSafe(strstr((char *)client->_data, "\r\n"));
|
||||
boolean notFinished(true);
|
||||
|
||||
//In the case where we have cookies followed by post data, there was an issue were we mistaken the = from the cookie separator with the = of the post data separator.
|
||||
//Here just in case of the last cookie value finishing with a ';'
|
||||
if(failSafe)
|
||||
return false;
|
||||
|
||||
//There is at least one key/value pair
|
||||
if(endOfKey)
|
||||
{
|
||||
*endOfKey = '\0';
|
||||
endOfKey++;
|
||||
|
||||
if(endOfValue)
|
||||
{
|
||||
*endOfValue = '\0';
|
||||
}
|
||||
else
|
||||
{
|
||||
endOfValue = endOfKey + strlen(endOfKey) + 1;
|
||||
notFinished = false;
|
||||
}
|
||||
#ifdef DEBUG_WEBS
|
||||
Serial.printf("Key -> Value : #%s# Value : #%s#\n", ((char)*client->_data == ' ') ? (char*)client->_data + 1 : (char*)client->_data , endOfKey);
|
||||
#endif
|
||||
client->_httpRequestData.cookies.add(((char)*client->_data == ' ') ? (char*)client->_data + 1 : (char*)client->_data, new HttpCookie({endOfKey}));
|
||||
//We dont forget to free the parsed data
|
||||
client->freeDataBuffer((endOfValue + 1 - (char *)client->_data));
|
||||
return notFinished;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void sendDataToClient(T *client)
|
||||
{
|
||||
if(!sendPageToClientFromApiDictio(client)) //Then we check if it is not a file that is requested
|
||||
@ -1109,10 +1210,19 @@ class WEBServer : public TCPServer<T>, public HttpConstants
|
||||
void *pData;
|
||||
HttpRequestMethod HRM;
|
||||
};
|
||||
|
||||
//Server side http cookie handling
|
||||
struct ServerHttpCookie : public HttpCookie
|
||||
{
|
||||
DictionaryHelper::StringEntity domain;
|
||||
DictionaryHelper::StringEntity path;
|
||||
int32_t sameSite : 1, httpOnly : 1, maxAge : 30;
|
||||
//Need to add the expires field as well. Thinking about the best way of doing it.
|
||||
};
|
||||
|
||||
Dictionary<ApiRoutine> _apiDictionary;
|
||||
Dictionary<DictionaryHelper::StringEntity> _httpHeadersDictionary;
|
||||
Dictionary<HttpCookie> _setCookieDictionary;
|
||||
Dictionary<ServerHttpCookie> _setCookieDictionary;
|
||||
SDClass *_sdClass;
|
||||
char *_WWWDir = nullptr; //Website root folder
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user