diff --git a/CMakeLists.txt b/CMakeLists.txt index d6d059d..183726f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -78,7 +78,7 @@ target_link_libraries( ${PYTHON_LIBRARIES} ${Boost_LIBRARIES} nlohmann_json::nlohmann_json - libhttp + httpparser ) # add custom targets @@ -86,22 +86,22 @@ add_custom_target( ProjectHeaderFiles SOURCES ./src/Helper.hpp - ./src//Global.hpp - ./src//Server.hpp - ./src//Client.hpp - ./src//Filesystem.hpp - ./src//Configuration.hpp - ./src//MemoryManager.hpp - ./src//ThreadHandler.hpp - ./src//IPCHandler.hpp - ./src//IPCHandlerAS.hpp - ./src//ClientHandler.hpp - ./src//ASProcessHandler.hpp - ./src//ASRequestHandler.hpp - ./src//ResultProcessor.hpp - ./src//ResultOrder.hpp - ./src//Constant.hpp - ./src//Vector.hpp + ./src/Global.hpp + ./src/Server.hpp + ./src/Client.hpp + ./src/Filesystem.hpp + ./src/Configuration.hpp + ./src/MemoryManager.hpp + ./src/ThreadHandler.hpp + ./src/IPCHandler.hpp + ./src/IPCHandlerAS.hpp + ./src/ClientHandler.hpp + ./src/ASProcessHandler.hpp + ./src/ASRequestHandler.hpp + ./src/ResultProcessor.hpp + ./src/ResultOrder.hpp + ./src/Constant.hpp + ./src/Vector.hpp ) # add subdirs diff --git a/lib/http/CMakeLists.txt b/lib/http/CMakeLists.txt index e7708e8..5bfdb94 100644 --- a/lib/http/CMakeLists.txt +++ b/lib/http/CMakeLists.txt @@ -1,22 +1,25 @@ -# find boost::python -find_package(Boost 1.74 REQUIRED COMPONENTS regex) - # add source dir aux_source_directory(. SRC_LIST_LIBHTTP) # add library -add_library(libhttp STATIC ${SRC_LIST_LIBHTTP}) +add_library(httpparser STATIC ${SRC_LIST_LIBHTTP}) # add lib parser and network add_custom_target( - libhttpheader + httpparserheader SOURCES ./httpparser.hpp - ./httpnet.hpp ) -# set target link libraries -target_link_libraries(libhttp ${Boost_LIBRARIES}) +# install static .a library +install( + TARGETS httpparser + LIBRARY DESTINATION /usr/local/lib +) -# install -install(TARGETS libhttp DESTINATION lib) +# install header file +install( + FILES + ./httpparser.hpp + DESTINATION /usr/local/include +) diff --git a/lib/http/httpconstants.hpp b/lib/http/httpconstants.hpp new file mode 100644 index 0000000..b524666 --- /dev/null +++ b/lib/http/httpconstants.hpp @@ -0,0 +1,35 @@ +#pragma once + +#include +#include +#include + +//- constant expressions +constexpr uint16_t HTTP_VERSION_UNKNOWN = 0; +constexpr uint16_t HTTP_VERSION_1_1 = 1; + +constexpr uint16_t HTTP_METHOD_OTHER = 0; +constexpr uint16_t HTTP_METHOD_GET = 1; +constexpr uint16_t HTTP_METHOD_POST = 2; + +constexpr uint16_t HTTP_POST_MAX_CONTENT_LENGTH = 4096; + +constexpr uint16_t URL_PARAM_NOT_FOUND_ERROR = 10; + +//- constant expressions (error) +constexpr uint16_t HTTP_ERROR_PARSE_BUFFER_EXCEEDED = 10; +constexpr uint16_t HTTP_ERROR_BAD_REQUEST = 400; + +//- contant strings +static const std::string HTTP_1_1_END_MARKER("\r\n\r\n"); +static const std::string HTTP_HEADER_CONTENT_LENGTH("Content-Length"); + +//- contant multidimensional +static const std::vector HTTPHeaderTypes +{ + "Host", + "Transfer-Encoding", + "If-None-Match", + "Content-Type", + HTTP_HEADER_CONTENT_LENGTH +}; diff --git a/lib/http/httpnet.cpp b/lib/http/httpnet.cpp deleted file mode 100644 index 2d96bdb..0000000 --- a/lib/http/httpnet.cpp +++ /dev/null @@ -1,15 +0,0 @@ -#include "httpnet.hpp" - -using namespace std; - - -HTTPNet::HTTPNet() -{ - DBG(120, "Constructor"); -} - -HTTPNet::~HTTPNet() -{ - DBG(120, "Destructor"); -} - diff --git a/lib/http/httpnet.hpp b/lib/http/httpnet.hpp deleted file mode 100644 index 6a0b108..0000000 --- a/lib/http/httpnet.hpp +++ /dev/null @@ -1,26 +0,0 @@ -#ifndef LibHTTP_net_hpp -#define LibHTTP_net_hpp - -#include - -#include "../../src/Debug.cpp" -#include "../../src/Helper.hpp" - -#include - -class HTTPNet -{ - -public: - - HTTPNet(); - ~HTTPNet(); - - -private: - -protected: - -}; - -#endif diff --git a/lib/http/httpparser.cpp b/lib/http/httpparser.cpp index a289122..f137141 100644 --- a/lib/http/httpparser.cpp +++ b/lib/http/httpparser.cpp @@ -3,268 +3,163 @@ using namespace std; -HTTPParser::HTTPParser(ClientFD_t ClientFD, NamespacesRef_t NamespacesRef) : - Client(ClientFD), - _Namespaces(NamespacesRef), - _RequestCount(0), +HTTPParser::HTTPParser(const uint16_t BufferSize) : _RequestCountGet(0), _RequestCountPost(0), - _RequestCountPostAS(0), + _RequestParseError(0), + _POSTWaitContentLength(false), + _POSTContentLength(0), _HTTPRequestBuffer("") { - DBG(120, "Constructor"); - _HTTPRequestBuffer.reserve(BUFFER_BYTES); + _HTTPRequestBuffer.reserve(BufferSize); + _HTTPRequestBufferMax = BufferSize; } HTTPParser::~HTTPParser() { - DBG(120, "Destructor"); } -void HTTPParser::appendBuffer(const char* BufferRef, const uint16_t BufferSize) +void HTTPParser::appendBuffer(const char* BufferRef, const uint16_t RecvBytes) { - //-> reset _SplittedRequests vector - _SplittedRequests.clear(); + if (_HTTPRequestBuffer.length()+RecvBytes > _HTTPRequestBufferMax) { + return; + } - //- workaround - if (BufferRef[0] == 0) { return; } + _HTTPRequestBuffer.append(BufferRef, RecvBytes); - DBG(250, "size:" << string(BufferRef).length() << "appendBuffer:'" << string(BufferRef) << "'"); - _HTTPRequestBuffer = _HTTPRequestBuffer + string(BufferRef); - //String::hexout(_HTTPRequestBuffer); - DBG(250, "_HTTPRequestBuffer:'" << _HTTPRequestBuffer << "'"); + //- on incomplete (single) POST request + if (_POSTWaitContentLength == true && _HTTPRequestBuffer.length() >= _POSTContentLength) { + _RequestProperties.Payload = _HTTPRequestBuffer.substr(0, _POSTContentLength); + _HTTPRequestBuffer.replace(0, _POSTContentLength, ""); + _Requests.push_back(move(_RequestProperties)); + _POSTWaitContentLength = false; + } + else { + //- reset _SplittedRequests vector + _SplittedRequests.clear(); - //-> only process on min 1 valid request - const size_t EndMarkerFound = _HTTPRequestBuffer.find("\r\n\r\n"); + //- only process on minimum of 1 http request (end marker found) + const size_t EndMarkerFound = _HTTPRequestBuffer.find(HTTP_1_1_END_MARKER); - if (EndMarkerFound != string::npos) { - _splitRequests(); + if (EndMarkerFound != string::npos) { + _processRequests(); + } } } -inline void HTTPParser::_splitRequests() +RequestsVector_t HTTPParser::getRequests() { - //DBG(180, "splitRequests Buffer:'" << _HTTPRequestBuffer << "'"); - - //- reset request counters - _RequestCountGet = 0; - _RequestCountPost = 0; - _RequestCountPostAS = 0; - _RequestNumber = 1; - - //-> split requests into _SplittedRequests vector - String::split(_HTTPRequestBuffer, "\r\n\r\n", _SplittedRequests); - - _RequestCount = _SplittedRequests.size(); - DBG(120, "splitRequests count after splitted into Vector:" << _RequestCount); - DBG(120, "_HTTPRequestBuffer after split:'" << _HTTPRequestBuffer << "'"); + return _Requests; } -size_t HTTPParser::processRequests(SharedMemAddress_t SHMGetRequests, const ASRequestHandlerRef_t& ASRequestHandlerRef) +void HTTPParser::getNextRequest(RequestPropertiesRef_t Request) { - DBG(250, "_HTTPRequestBuffer:'" << _HTTPRequestBuffer << "'"); + if (_Requests.size() > 0) { + Request = move(_Requests.front()); + _Requests.erase(_Requests.begin()); + } +} - //- set get requests SHM base - setBaseAddress(SHMGetRequests); +inline void HTTPParser::_processRequests() +{ + //- split requests into _SplittedRequests vector + StringHelper::split(_HTTPRequestBuffer, HTTP_1_1_END_MARKER, _SplittedRequests); //- iterate over splitted requests for(size_t i=0; i<_SplittedRequests.size(); ++i) { - _processRequestProperties(i, ASRequestHandlerRef); + if (_processRequestProperties(i) == false) { + _RequestParseError = HTTP_ERROR_BAD_REQUEST; + break; + } } - - return _RequestCountGet; } -void HTTPParser::_processRequestProperties(const size_t Index, const ASRequestHandlerRef_t& ASRequestHandlerRef) +inline bool HTTPParser::_processRequestProperties(const size_t Index) { //- get request ref at vector index auto &Request = _SplittedRequests.at(Index); //- on empty request return - if (Request.empty()) { return; } - - DBG(140, "Processing Index:" << Index << " Request:'" << Request << "'"); - - BasePropsResult_t BasePropsFound; - _parseRequestProperties(Request, BasePropsFound); - - DBG(140, "HTTP Version:" << BasePropsFound.at(0) << " File:" << BasePropsFound.at(1) << " Method:" << BasePropsFound.at(2)); - DBG(140, "Complete Request:" << Request.c_str()); - - //- temp hardcode HTTPVersion - uint16_t HTTPVersion = 1; - - //- check HTTP/1.2 or HTTP/1.2 (currently unimplemented) - const size_t HTTPVersion1_1Found = BasePropsFound.at(0).find("HTTP/1.1"); - const size_t HTTPVersion1_2Found = BasePropsFound.at(2).find("HTTP/1.2"); + if (Request.empty()) { return false; } - //- if not HTTP/1.1 set request to "" in vector element, return - if (HTTPVersion1_1Found == string::npos) { return; } + //- init unparsed base properties with default values + _RequestProperties = { + .HTTPVersion = HTTP_VERSION_UNKNOWN, + .HTTPMethod = HTTP_METHOD_OTHER, + .URL = "/" + }; - //- check for method GET || POST - const size_t HTTPMethodPOST = BasePropsFound.at(2).find("POST"); - const size_t HTTPMethodGET = BasePropsFound.at(2).find("GET"); + //- parse base properties + _parseRequestProperties(Request, _RequestProperties); - //- set numerical http method (GET: 1, POST: 2) - uint16_t HTTPMethod = 0; + //- only process HTTP/1.1 requests + if (_RequestProperties.HTTPVersion != HTTP_VERSION_1_1) { return false; } - if (HTTPMethodGET != string::npos) { HTTPMethod = 1; } - if (HTTPMethodPOST != string::npos) { HTTPMethod = 2; } - DBG(140, "HTTPMethod:" << HTTPMethod); + //- if not GET || POST method, return + if (_RequestProperties.HTTPMethod == HTTP_METHOD_OTHER) { return false; } - //- if not GET || POST, return - if (HTTPMethod == 0) { return; } + //- parse request headers + _parseRequestHeaders(Request, _RequestProperties.RequestHeaders); - //- check if POST request is a POSTAS request - const size_t AppServerReqFound = BasePropsFound.at(1).find("/backend/"); - - //- if not POSTAS, return - if (HTTPMethod == 2 && AppServerReqFound == string::npos) { - ++_RequestCountPost; - return; - } - - //- get unique request nr - const uint16_t RequestNr = _RequestNumber; - ++_RequestNumber; - - DBG(140, "HTTP RequestNr:" << RequestNr); - - RequestHeaderResult_t Headers; - - //- AS GET request - if (HTTPMethod == 1 && AppServerReqFound != string::npos) { - - //- parse request headers - _parseRequestHeaders(Request, Headers); - - const NamespaceProps_t NamespaceProps = _Namespaces.at(Headers.at("Host")); - string JSONPayload("{ \"payload\": {"); - - for (const auto& [Endpoint, EndpointProps]: NamespaceProps.JSONConfig["access"]["as-get"].items()) { - DBG(200, "Endpoint:" << Endpoint); - const size_t EndpointFound = BasePropsFound.at(1).find("/backend" + Endpoint); - if (EndpointFound != string::npos) { - DBG(200, "Looping on params"); - string ProcessURL = BasePropsFound.at(1); - for (size_t i=0; i HTTP_POST_MAX_CONTENT_LENGTH) { + return false; } - bool PayloadFound = false; - string Payload = ""; - - //- try payload in next (vector index +1) request - try { - auto &NextRequest = _SplittedRequests.at(Index+1); - if (NextRequest.length() >= ContentBytes) { - Payload = NextRequest.substr(0, ContentBytes); - NextRequest.replace(0, ContentBytes, ""); - PayloadFound = true; + //- on single HTTP POST: payload after endmarker in _HTTPRequestBuffer + if (_SplittedRequests.size() == 1) { + //- content length bytes already in buffer + if (_HTTPRequestBuffer.length() >= _POSTContentLength) { + _RequestProperties.Payload = _HTTPRequestBuffer.substr(0, _POSTContentLength); + _HTTPRequestBuffer.replace(0, _POSTContentLength, ""); + _Requests.push_back(move(_RequestProperties)); } - } - catch(const std::exception& e) { - DBG(200, "Next vector does not exist, trying in rest of _HTTPRequestBuffer"); - //- try payload in _HTTPRequestBuffer - if (_HTTPRequestBuffer.length() >= ContentBytes) { - Payload = _HTTPRequestBuffer.substr(0, ContentBytes); - _HTTPRequestBuffer.replace(0, ContentBytes, ""); - PayloadFound = true; + else { + //- set flag to wait until content-length reached + _POSTWaitContentLength = true; } } - - DBG(140, "HTTP POST-AS Payload:" << Payload); - - if (PayloadFound) { - _processASPayload( - ASRequestHandlerRef, Headers, HTTPMethod, HTTPVersion, RequestNr, Payload - ); + //- otherwise payload in next splitted message + else if (_SplittedRequests.size() > Index) { + auto &NextRequest = _SplittedRequests.at(Index+1); + if (NextRequest.length() >= _POSTContentLength) { + _RequestProperties.Payload = NextRequest.substr(0, _POSTContentLength); + NextRequest.replace(0, _POSTContentLength, ""); + _Requests.push_back(move(_RequestProperties)); + } + else { + return false; + } } } - - //- Standard GET request - if (HTTPMethod == 1 && AppServerReqFound == string::npos) { - - DBG(140, "Request Type GET:" << Request); - - ++_RequestCountGet; - - //- set values in get requests shared memory - const char* MsgCString = Request.c_str(); - - void* ClientFDAddr = getCurrentOffsetAddress(); - void* HTTPVersionAddr = getNextAddress(); - void* RequestNrAddr = getNextAddress(); - void* MsgLengthAddr = getNextAddress(); - - new(HTTPVersionAddr) uint16_t(HTTPVersion); - new(RequestNrAddr) uint16_t(RequestNr); - new(ClientFDAddr) ClientFD_t(_ClientFD); - - uint16_t MsgLength = Request.length(); - new(MsgLengthAddr) uint16_t(MsgLength); - - void* MsgAddress = getNextAddress(); - memcpy(MsgAddress, &MsgCString[0], MsgLength); - - void* NextSegmentAddr = getNextAddress(MsgLength); - DBG(120, "Set SharedMem ClientFD:" << ClientFDAddr << " PayloadLength:" << MsgLengthAddr << " Payload:" << MsgAddress << " NextSegment:" << NextSegmentAddr); - } + return true; } -void HTTPParser::_parseRequestProperties(string& Request, BasePropsResultRef_t ResultRef) +inline void HTTPParser::_parseRequestProperties(string& Request, RequestPropertiesRef_t ResultBaseProps) { - DBG(120, "HTTP Request:'" << Request << "'"); - //- find first line endline size_t StartPos = Request.find("\r\n"); @@ -273,111 +168,45 @@ void HTTPParser::_parseRequestProperties(string& Request, BasePropsResultRef_t R StartPos = Request.length(); } - //- reverse split - String::rsplit(Request, StartPos, " ", ResultRef); + //- get base request properties + vector SplitResult; + StringHelper::rsplit(Request, StartPos, " ", SplitResult); + + if (SplitResult.at(0).find("HTTP/1.1") != string::npos) { + ResultBaseProps.HTTPVersion = HTTP_VERSION_1_1; + } + + if (SplitResult.at(2).find("GET") != string::npos) { + ResultBaseProps.HTTPMethod = HTTP_METHOD_GET; + } + else if (SplitResult.at(2).find("POST") != string::npos) { + ResultBaseProps.HTTPMethod = HTTP_METHOD_POST; + } - DBG(120, "HTTP Version:" << ResultRef.at(0) << " File:" << ResultRef.at(1) << " Method:" << ResultRef.at(2) << " Request:" << Request); + ResultBaseProps.URL = SplitResult.at(1); } -void HTTPParser::_parseRequestHeaders(string& Request, RequestHeaderResultRef_t ResultRef) +inline void HTTPParser::_parseRequestHeaders(string& Request, RequestHeaderRef_t ResultRef) { - DBG(120, "HTTP Request:'" << Request << "'"); - //- reverse split header lines vector Lines; - String::split(Request, "\r\n", Lines); + StringHelper::split(Request, "\r\n", Lines); - DBG(120, "Last Header Line:'" << Request << "'"); Lines.push_back(Request); //- loop over lines, split, put into result map for (auto &Line:Lines) { - DBG(120, "Line:'" << Line << "'"); - vector HeaderPair; if (Line.find(":") != string::npos) { - String::rsplit(Line, Line.length(), ": ", HeaderPair); + StringHelper::rsplit(Line, Line.length(), ": ", HeaderPair); string HeaderID = HeaderPair.at(1); string HeaderValue = HeaderPair.at(0).substr(0, HeaderPair.at(0).length()); - DBG(120, "HeaderID:'" << HeaderID << "'"); - DBG(120, "HeaderValue:'" << HeaderValue << "'"); - ResultRef.emplace( HeaderID, HeaderValue ); } } - DBG(120, "End parse headers."); -} - -inline string HTTPParser::_getASURLParamValue( - const string& Param, - const uint16_t Index, - string& ReqURL -){ - DBG(200, "ReqURL:" << ReqURL); - //- process first ? parameter - if (Index == 0) { - const size_t StartMarkerPos = ReqURL.find("?"); - const size_t MidMarkerPos = ReqURL.find("="); - const size_t EndMarkerPos = ReqURL.find("&"); - const size_t CompletePos = ReqURL.find("?" + Param + "="); - const size_t CheckMidPos = CompletePos+Param.size()+1; - - if (CompletePos != string::npos && StartMarkerPos != string::npos && MidMarkerPos != string::npos && MidMarkerPos == CheckMidPos) { - const size_t EndPos = (EndMarkerPos == string::npos) ? ReqURL.size() : EndMarkerPos; - const string ReturnString = ReqURL.substr(MidMarkerPos+1, EndPos-(MidMarkerPos+1)); - DBG(200, "ReqURL StartMarkerPos:" << StartMarkerPos << " EndPos:" << EndPos); - ReqURL.replace(StartMarkerPos, EndPos-StartMarkerPos, ""); - return ReturnString; - } - else { - return "not-found"; - } - } - //- process next & parameter(s) - if (Index > 0) { - const size_t StartMarkerPos = ReqURL.find("&"); - const size_t MidMarkerPos = ReqURL.find("="); - const size_t CompletePos = ReqURL.find("&" + Param + "="); - const size_t CheckMidPos = CompletePos+Param.size()+1; - - if (CompletePos != string::npos && StartMarkerPos != string::npos && MidMarkerPos != string::npos && MidMarkerPos == CheckMidPos) { - const size_t NextMarkerPos = ReqURL.find("&", MidMarkerPos); - const size_t EndPos = (NextMarkerPos == string::npos) ? ReqURL.size() : NextMarkerPos; - const string ReturnString = ReqURL.substr(MidMarkerPos+1, EndPos-(MidMarkerPos+1)); - DBG(200, "ReqURL StartMarkerPos:" << StartMarkerPos << " EndPos:" << EndPos); - ReqURL.replace(StartMarkerPos, EndPos-StartMarkerPos, ""); - return ReturnString; - } - else { - return "not-found"; - } - } - return "parse-error"; -} - -inline void HTTPParser::_processASPayload( - const ASRequestHandlerRef_t& ASRequestHandlerRef, - const RequestHeaderResult_t& Headers, - const uint16_t HTTPMethod, - const uint16_t HTTPVersion, - const uint16_t RequestNr, - const string& Payload -){ - //- increment request count - ++_RequestCountPostAS; - - //- add ASRequestHandler request - ASRequestHandlerRef->addRequest({ - Headers.at("Host"), - _ClientFD, - HTTPMethod, - HTTPVersion, - RequestNr, - Payload - }); } diff --git a/lib/http/httpparser.hpp b/lib/http/httpparser.hpp index c01dbbe..6567ccc 100644 --- a/lib/http/httpparser.hpp +++ b/lib/http/httpparser.hpp @@ -1,85 +1,151 @@ -#ifndef LibHTTP_parser_hpp -#define LibHTTP_parser_hpp -#include "../../src/Debug.cpp" -#include "../../src/Helper.hpp" -#include "../../src/IPCHandler.hpp" -#include "../../src/IPCHandlerAS.hpp" -#include "../../src/ASRequestHandler.hpp" -#include "../../src/Client.hpp" +#pragma once + +#include "httpconstants.hpp" #include +#include +#include +#include +#include +using namespace std; -typedef pair HeaderPair_t; typedef unordered_map RequestHeader_t; +typedef RequestHeader_t& RequestHeaderRef_t; -typedef RequestHeader_t RequestHeaderResult_t; -typedef RequestHeader_t& RequestHeaderResultRef_t; - -typedef vector BasePropsResult_t; -typedef BasePropsResult_t& BasePropsResultRef_t; - +typedef unordered_map URLParam_t; -static const vector HeaderList +struct RequestProperties_t { - "Host", - "Request-UUID", - "Transfer-Encoding", - "If-None-Match", - "Content-Type", - "Content-Length" + uint16_t HTTPVersion; + uint16_t HTTPMethod; + RequestHeader_t RequestHeaders; + string URL; + string Payload; + URLParam_t URLParams; }; +typedef RequestProperties_t& RequestPropertiesRef_t; + +typedef vector RequestsVector_t; + -class HTTPParser: private Client, private SHMStaticFS, private SHMPythonAS +class HTTPParser { public: - HTTPParser(const ClientFD_t, const NamespacesRef_t); + HTTPParser(const uint16_t); ~HTTPParser(); void appendBuffer(const char*, const uint16_t); - size_t processRequests(SharedMemAddress_t, const ASRequestHandlerRef_t&); + RequestsVector_t getRequests(); + void getNextRequest(RequestPropertiesRef_t); private: - inline void _splitRequests(); - void _processRequestProperties(const size_t, const ASRequestHandlerRef_t&); + void _processRequests(); + bool _processRequestProperties(const size_t); RequestHeader_t _RequestHeaders; vector _SplittedRequests; - NamespacesRef_t _Namespaces; - - size_t _RequestCount; size_t _RequestCountGet; size_t _RequestCountPost; - size_t _RequestCountPostAS; - uint16_t _RequestNumber; + uint16_t _RequestParseError; + + bool _POSTWaitContentLength; + uint16_t _POSTContentLength; string _HTTPRequestBuffer; + uint16_t _HTTPRequestBufferMax; + + RequestProperties_t _RequestProperties; + RequestsVector_t _Requests; protected: - void _parseRequestProperties(string&, BasePropsResultRef_t); - void _parseRequestHeaders(string&, RequestHeaderResultRef_t); - - inline string _getASURLParamValue( - const string&, - const uint16_t, - string& - ); - - inline void _processASPayload( - const ASRequestHandlerRef_t&, - const RequestHeaderResult_t&, - const uint16_t, - const uint16_t, - const uint16_t, - const string& - ); + void _parseRequestProperties(string&, RequestPropertiesRef_t); + void _parseRequestHeaders(string&, RequestHeaderRef_t); }; -#endif + +class StringHelper { + +public: + + static void split(string& StringRef, const string Delimiter, vector& ResultRef, bool EraseFromSrc = true) + { + string SplitElement; + auto pos = StringRef.find(Delimiter); + + while (pos != string::npos) { + SplitElement = StringRef.substr(0, pos); + ResultRef.push_back(SplitElement); + if (EraseFromSrc == true) { + StringRef.erase(0, pos + Delimiter.length()); + } + pos = StringRef.find(Delimiter); + } + } + + static void rsplit(string& String, size_t StartPos, const string Delimiter, vector& ResultRef) + { + size_t FindPos = 0; + size_t FindPosLast = 0; + string Token; + StartPos -= Delimiter.length(); + while ((FindPos = String.rfind(Delimiter, StartPos)) != String.npos) { + Token = String.substr(FindPos+Delimiter.length(), (StartPos-FindPos)); + ResultRef.push_back(Token); + StartPos = FindPos - Delimiter.length(); + FindPosLast = FindPos; + } + Token = String.substr(0, FindPosLast); + ResultRef.push_back(Token); + } + + static bool is_digits(const string& checkdigits) + { + return all_of(checkdigits.begin(), checkdigits.end(), ::isdigit); + } + +}; + +class JSON { + +public: + + static void getRequest2JSON() + { + /* + const NamespaceProps_t NamespaceProps = _Namespaces.at(Headers.at("Host")); + string JSONPayload("{ \"payload\": {"); + + for (const auto& [Endpoint, EndpointProps]: NamespaceProps.JSONConfig["access"]["as-get"].items()) { + DBG(200, "Endpoint:" << Endpoint); + const size_t EndpointFound = BaseProperties.at(1).find("/backend" + Endpoint); + if (EndpointFound != string::npos) { + DBG(200, "Looping on params"); + string ProcessURL = BaseProperties.at(1); + for (size_t i=0; i #include #include - typedef uint16_t ClientFD_t; typedef uint16_t ClientRequestNr_t; - -class Client +class Client : public HTTPParser { public: @@ -20,7 +18,8 @@ class Client Client(ClientFD_t); ~Client(); - ClientRequestNr_t getNextReqNr(); + void incrementReqNr(); + ClientRequestNr_t getCurrentReqNr(); protected: @@ -29,17 +28,6 @@ class Client private: ClientRequestNr_t _RequestNr; - - bool _Error; - uint16_t _ErrorID; - - time_t _RequestStartTime; - time_t _RequestEndTime; - time_t _ResponseStartTime; - time_t _ResponseEndTime; - - bool _TimeoutReached; - + time_t _SocketConnectTime; + time_t _SocketDisconnectTime; }; - -#endif diff --git a/src/ClientHandler.cpp b/src/ClientHandler.cpp index 53f24eb..b478e2e 100644 --- a/src/ClientHandler.cpp +++ b/src/ClientHandler.cpp @@ -48,11 +48,15 @@ void ClientHandler::addClient(const uint16_t ClientFD) //- set client connection non blocking Socket::makeNonblocking(ClientFD); - ClientRef_t ClientObj = std::make_shared(ClientFD, ConfigRef.Namespaces); + //ClientRef_t ClientObj = std::make_shared(ClientFD); + Client_t ClientObj(ClientFD); + /* Clients.emplace( - ClientFD, ClientObj + ClientFD, move(ClientObj) ); + */ + ClientsVector.push_back(move(ClientObj)); //- add fd to epoll EpollEvent.events = EPOLLIN | EPOLLET; @@ -121,12 +125,15 @@ void ClientHandler::readClientData(const uint16_t FDCount) else { //- if filedescriptor exists in map, append buffer data if (Clients.contains(ReadFD)) { - ClientRef_t ClientRef = Clients[ReadFD]; - ClientRef->appendBuffer(Buffer, RcvBytes); + //Clients[ReadFD].appendBuffer(Buffer, RcvBytes); + ClientsVector[0].appendBuffer(Buffer, RcvBytes); + + /* if (ClientRef->processRequests(SHMGetRequests, _ASRequestHandlerRef) > 0) { ++ProcessedClients; } + */ } } } diff --git a/src/ClientHandler.hpp b/src/ClientHandler.hpp index 8c03e21..17f1a17 100644 --- a/src/ClientHandler.hpp +++ b/src/ClientHandler.hpp @@ -1,5 +1,4 @@ -#ifndef ClientHandler_hpp -#define ClientHandler_hpp +#pragma once #include "Debug.cpp" @@ -17,12 +16,14 @@ #include "MemoryManager.hpp" #include "ASRequestHandler.hpp" -#include "../lib/http/httpparser.hpp" +//typedef std::shared_ptr ClientRef_t; +//typedef pair ClientMapPair_t; +typedef Client Client_t; +typedef Client& ClientRef_t; -typedef std::shared_ptr ClientRef_t; -typedef pair ClientMapPair_t; -typedef unordered_map ClientMap_t; +typedef unordered_map ClientMap_t; +typedef vector ClientVector_t; typedef struct { void* StaticFSPtr; @@ -54,6 +55,7 @@ class ClientHandler private: ClientMap_t Clients; + ClientVector_t ClientsVector; struct epoll_event EpollEvent, EpollEvents[EPOLL_FD_COUNT_MAX]; @@ -70,5 +72,3 @@ class ClientHandler ASRequestHandlerRef_t _ASRequestHandlerRef; }; - -#endif diff --git a/src/Helper.hpp b/src/Helper.hpp index b5ab8d9..aa60c7c 100644 --- a/src/Helper.hpp +++ b/src/Helper.hpp @@ -57,42 +57,6 @@ class String { public: - static void split(string& StringRef, const string Delimiter, vector& ResultRef) - { - string SplitElement; - auto pos = StringRef.find(Delimiter); - - while (pos != string::npos) { - SplitElement = StringRef.substr(0, pos); - DBG(220, "SplitElement:'" << SplitElement << "'"); - ResultRef.push_back(SplitElement); - StringRef.erase(0, pos + Delimiter.length()); - pos = StringRef.find(Delimiter); - } - - DBG(200, "String:'" << StringRef << "'"); - } - - //- TODO: ugly, refactor (lambda?) - static void rsplit(string& String, size_t StartPos, const string Delimiter, vector& ResultRef) - { - size_t FindPos = 0; - size_t FindPosLast = 0; - string Token; - StartPos -= Delimiter.length(); - while ((FindPos = String.rfind(Delimiter, StartPos)) != String.npos) { - DBG(200, "FindPos:" << FindPos << " StartPos:" << StartPos); - Token = String.substr(FindPos+Delimiter.length(), (StartPos-FindPos)); - DBG(200, "Token:" << Token); - ResultRef.push_back(Token); - StartPos = FindPos - Delimiter.length(); - FindPosLast = FindPos; - } - DBG(200, "End FindPos:" << FindPosLast); - Token = String.substr(0, FindPosLast); - ResultRef.push_back(Token); - } - static void hexout(string& String) { for (auto i = String.begin(); i != String.end(); ++i) { diff --git a/src/ResultProcessor.hpp b/src/ResultProcessor.hpp index ba93768..88c2f1f 100644 --- a/src/ResultProcessor.hpp +++ b/src/ResultProcessor.hpp @@ -1,5 +1,4 @@ -#ifndef ResultProcessor_hpp -#define ResultProcessor_hpp +#pragma once #include #include @@ -15,6 +14,7 @@ #include "IPCHandler.hpp" #include "Configuration.hpp" #include "ResultOrder.hpp" +#include "ASProcessHandler.hpp" typedef struct { void* StaticFSPtr; @@ -50,5 +50,3 @@ class ResultProcessor : private SHMStaticFS, public CPU, private ResultOrder, pr VHostOffsetsPrecalc_t _VHostOffsetsPrecalc; }; - -#endif diff --git a/src/ThreadHandler.cpp b/src/ThreadHandler.cpp index fd86efe..11b606f 100644 --- a/src/ThreadHandler.cpp +++ b/src/ThreadHandler.cpp @@ -97,7 +97,7 @@ ClientThread::ClientThread( Namespaces_t &Namespaces, ClientRequestDataVec_t Requests ) : - HTTPParser(ClientFD, Namespaces), + HTTPParser(4096), _ClientFD(ClientFD), _Namespaces(Namespaces), _ClientRequests(Requests) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index df9d207..1011064 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -1,12 +1,8 @@ # find boost unittest package find_package(Boost COMPONENTS unit_test_framework REQUIRED) -# find qt6 package -#find_package(Qt6 REQUIRED COMPONENTS Core Test) - # add subdirs add_subdirectory(eval) add_subdirectory(integration) add_subdirectory(unit) add_subdirectory(performance) - diff --git a/test/integration/CMakeLists.txt b/test/integration/CMakeLists.txt index 0d0396e..6d6cc44 100644 --- a/test/integration/CMakeLists.txt +++ b/test/integration/CMakeLists.txt @@ -1,6 +1,5 @@ # add subdirs add_subdirectory(event) -add_subdirectory(boost-regex) add_subdirectory(string-functions) add_subdirectory(vector-multi-erase) add_subdirectory(signal-termination) diff --git a/test/integration/boost-regex/CMakeLists.txt b/test/integration/boost-regex/CMakeLists.txt deleted file mode 100644 index 229ef65..0000000 --- a/test/integration/boost-regex/CMakeLists.txt +++ /dev/null @@ -1,10 +0,0 @@ -# add source dir -aux_source_directory(. SRC_LIST_TEST_BOOST_REGEX) - -# find boost unittest package -find_package(Boost COMPONENTS regex REQUIRED) - -add_executable(test-boost-regex "test-boost-regex.cpp") - -target_link_libraries(test-boost-regex ${Boost_UNIT_TEST_FRAMEWORK_LIBRARY}) -target_link_libraries(test-boost-regex ${Boost_LIBRARIES}) diff --git a/test/integration/boost-regex/test-boost-regex.cpp b/test/integration/boost-regex/test-boost-regex.cpp deleted file mode 100644 index dade1a9..0000000 --- a/test/integration/boost-regex/test-boost-regex.cpp +++ /dev/null @@ -1,23 +0,0 @@ -#define BOOST_TEST_MAIN -#include - -#include - -using namespace std; -using namespace boost; - -BOOST_AUTO_TEST_CASE( test_regex_split ) -{ - - cout << "Check multiple Boost Regex variants." << endl; - - /* - //- does not work, c++20 does not implement list.push_back() - string Data("Test String \n\r Hello World\n\r Bla Bla"); - list ResultList; - list::iterator ListIter; - regex regexString{"\n\r"}; - regex_split(back_inserter(ListIter), Data, regexString); - */ - -} diff --git a/test/integration/string-functions/test-string-functions.cpp b/test/integration/string-functions/test-string-functions.cpp index d48b91c..1bf887a 100644 --- a/test/integration/string-functions/test-string-functions.cpp +++ b/test/integration/string-functions/test-string-functions.cpp @@ -2,6 +2,7 @@ #include #include "../../../src/Helper.hpp" +#include "../../../lib/http/httpparser.hpp" using namespace std; @@ -12,7 +13,7 @@ BOOST_AUTO_TEST_CASE( test_string_split_1 ) vector Result; string TestString1("TestValue1-TestValue2-TestValue3"); - String::split(TestString1, "-", Result); + StringHelper::split(TestString1, "-", Result); cout << "Res[0]:" << Result.at(0) << endl; cout << "Res[1]:" << Result.at(1) << endl; @@ -25,7 +26,7 @@ BOOST_AUTO_TEST_CASE( test_string_split_1 ) Result.clear(); string TestString2("TestHTTP1\n\rTestHTTP2\n\rTestHTTP3\n\n\rEnd"); - String::split(TestString2, "\n\r", Result); + StringHelper::split(TestString2, "\n\r", Result); cout << "Res[0]:" << Result.at(0) << endl; cout << "Res[1]:" << Result.at(1) << endl; @@ -44,7 +45,7 @@ BOOST_AUTO_TEST_CASE( test_string_split_remains ) vector Result; string TestString1("TestHTTP1\n\r"); - String::split(TestString1, "\n\r", Result); + StringHelper::split(TestString1, "\n\r", Result); cout << "Res[0]:" << Result.at(0) << endl; @@ -62,7 +63,7 @@ BOOST_AUTO_TEST_CASE( test_string_rsplit_1 ) string TestString1("GET /path/to/file.txt HTTP/1.1\n Continues \n Again... "); size_t StartPos = TestString1.find("\n"); - String::rsplit(TestString1, StartPos, " ", Result); + StringHelper::rsplit(TestString1, StartPos, " ", Result); cout << "Res[0]:" << Result.at(0) << endl; cout << "Res[1]:" << Result.at(1) << endl; @@ -76,7 +77,7 @@ BOOST_AUTO_TEST_CASE( test_string_rsplit_1 ) string TestString2("GET / HTTP/1.1\nHeader1: HeaderContent1\nHeader2: HeaderContent2\n\r"); size_t StartPos2 = TestString2.find("\n"); - String::rsplit(TestString2, StartPos2, " ", Result); + StringHelper::rsplit(TestString2, StartPos2, " ", Result); cout << "Res[0]:" << Result.at(0) << endl; cout << "Res[1]:" << Result.at(1) << endl; diff --git a/test/unit/http-parser/CMakeLists.txt b/test/unit/http-parser/CMakeLists.txt index 413eee5..c6fced0 100644 --- a/test/unit/http-parser/CMakeLists.txt +++ b/test/unit/http-parser/CMakeLists.txt @@ -4,10 +4,6 @@ aux_source_directory(. SRC_LIST_TEST_HTTPPARSER) add_executable( test-parser-requests "test-parser-requests.cpp" - ../../../src/Client.cpp - ../../../src/IPCHandler.cpp - ../../../src/IPCHandlerAS.cpp - ../../../src/ASRequestHandler.cpp ) # add custom targets @@ -19,6 +15,4 @@ add_custom_target( # link libraries target_link_libraries(test-parser-requests ${Boost_UNIT_TEST_FRAMEWORK_LIBRARY}) -target_link_libraries(test-parser-requests ${Boost_LIBRARIES}) -target_link_libraries(test-parser-requests ${PYTHON_LIBRARIES}) -target_link_libraries(test-parser-requests libhttp) +target_link_libraries(test-parser-requests httpparser) diff --git a/test/unit/http-parser/test-parser-requests.cpp b/test/unit/http-parser/test-parser-requests.cpp index 3b550a2..5f33da2 100644 --- a/test/unit/http-parser/test-parser-requests.cpp +++ b/test/unit/http-parser/test-parser-requests.cpp @@ -2,200 +2,428 @@ #include #include -#include "../../../src/Client.hpp" -#include "../../../src/ClientHandler.hpp" +#include "../../../lib/http/httpparser.hpp" using namespace std; -using json = nlohmann::json; +static const string HTTP_REQUEST_GET_SINGLE1("GET /test/test.png HTTP/1.1\r\nCustomHeader: one\r\n\r\n"); +static const string HTTP_REQUEST_GET_SINGLE2("GET /test/test2.png HTTP/1.1\r\nHost: test.dns\r\nAnotherHeader: two\r\n\r\n"); +static const string HTTP_REQUEST_GET_SINGLE3("GET /test/test3.png HTTP/1.1\r\nThirdHeader: three\r\n\r\n"); -BOOST_AUTO_TEST_CASE( test_single_get_request ) +static const string HTTP_REQUEST_POST_SINGLE("POST /backend/test1 HTTP/1.1\r\nHost: test.loalnet\r\nContent-Type: application/json\r\nContent-Length: 2\r\n\r\n{}"); + +static const string HTTP_REQUEST_POST_PARTIAL1("POST /other/path HTTP/1.1\r\nHost: test.loal"); +static const string HTTP_REQUEST_POST_PARTIAL2("net\r\nContent-Type: application/json\r\nContent-Length: 10\r"); +static const string HTTP_REQUEST_POST_PARTIAL3("\n\r\n{12345678}"); + + +BOOST_AUTO_TEST_CASE( test_single_valid_get_request_full_transmit ) +{ + cout << "Check single GET request (full buffer transmit at once)." << endl; + + RequestsVector_t Requests; + + unique_ptr parser = make_unique(4096); + + parser->appendBuffer(HTTP_REQUEST_GET_SINGLE1.c_str(), HTTP_REQUEST_GET_SINGLE1.length()); + Requests = parser->getRequests(); + + auto rs = Requests.size(); + auto rv = Requests.at(0).HTTPVersion; + auto rm = Requests.at(0).HTTPMethod; + auto ru = Requests.at(0).URL; + auto rh = Requests.at(0).RequestHeaders.at("CustomHeader"); + + cout << "Request size: " << rs << " version: " << rv << " method: " << rm << " URL: " << ru << " Header: " << rh << endl; + + BOOST_TEST(rs == 1); + BOOST_TEST(rv == 1); + BOOST_TEST(rm == 1); + BOOST_TEST(ru == "/test/test.png"); + BOOST_TEST(rh == "one"); + +} + +BOOST_AUTO_TEST_CASE( test_single_valid_get_request_1byte_transmit ) +{ + cout << "Check single GET request (1-byte buffer transmit)." << endl; + + RequestsVector_t Requests; + + unique_ptr parser = make_unique(4096); + + // Send data byte by byte + for (size_t i = 0; i < HTTP_REQUEST_GET_SINGLE1.length(); i++) { + parser->appendBuffer(HTTP_REQUEST_GET_SINGLE1.c_str() + i, 1); + } + Requests = parser->getRequests(); + + auto rs = Requests.size(); + auto rv = Requests.at(0).HTTPVersion; + auto rm = Requests.at(0).HTTPMethod; + auto ru = Requests.at(0).URL; + auto rh = Requests.at(0).RequestHeaders.at("CustomHeader"); + + cout << "Request size: " << rs << " version: " << rv << " method: " << rm << " URL: " << ru << " Header: " << rh << endl; + + BOOST_TEST(rs == 1); + BOOST_TEST(rv == 1); + BOOST_TEST(rm == 1); + BOOST_TEST(ru == "/test/test.png"); + BOOST_TEST(rh == "one"); + +} + +BOOST_AUTO_TEST_CASE( test_single_post_request_full_transmit ) { - cout << "Check single GET request." << endl; + cout << "Check single POST request (full buffer transmit at once)." << endl; - void* SHMBase = mmap(NULL, SHMEM_STATICFS_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0); - void* SHMGetRequests = static_cast(SHMBase) + sizeof(atomic_uint16_t) + sizeof(uint16_t); + RequestsVector_t Requests; - void* SHMASMeta = mmap(NULL, SHMEM_STATICFS_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0); - void* SHMASRequests = mmap(NULL, SHMEM_STATICFS_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0); - void* SHMASResults = mmap(NULL, SHMEM_STATICFS_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0); + unique_ptr parser = make_unique(4096); - const json JSONConfig = { { "interpreters", 2 }, { "path", "/test" } }; + parser->appendBuffer(HTTP_REQUEST_POST_SINGLE.c_str(), HTTP_REQUEST_POST_SINGLE.length()); + Requests = parser->getRequests(); - Namespaces_t Namespaces; - NamespaceProps_t NamespaceProps; - NamespaceProps.FilesystemRef = nullptr; - NamespaceProps.JSONConfig = JSONConfig; + auto rs = Requests.size(); + auto rv = Requests.at(0).HTTPVersion; + auto rm = Requests.at(0).HTTPMethod; + auto ru = Requests.at(0).URL; + auto rh = Requests.at(0).RequestHeaders.at("Host"); + auto rp = Requests.at(0).Payload; - Namespaces.emplace( - "test1", NamespaceProps - ); + cout << "Request size: " << rs << " version: " << rv << " method: " << rm << " URL: " << ru << " Header: " << rh << " Payload: " << rp << endl; - ASRequestHandlerRef_t ASRequestHandlerRef = std::make_unique( - Namespaces, - BaseAdresses_t{ SHMASMeta, SHMASRequests, SHMASResults } - ); + BOOST_TEST(rs == 1); + BOOST_TEST(rv == 1); + BOOST_TEST(rm == 2); + BOOST_TEST(ru == "/backend/test1"); + BOOST_TEST(rh == "test.loalnet"); + BOOST_TEST(rp == "{}"); +} + +BOOST_AUTO_TEST_CASE( test_single_post_request_1byte_transmit ) +{ + cout << "Check single POST request (1-byte buffer transmit)." << endl; + + RequestsVector_t Requests; + + unique_ptr parser = make_unique(4096); + + // Send data byte by byte + for (size_t i = 0; i < HTTP_REQUEST_POST_SINGLE.length(); i++) { + parser->appendBuffer(HTTP_REQUEST_POST_SINGLE.c_str() + i, 1); + } + Requests = parser->getRequests(); - ClientFD_t ClientFD = 1; - ClientRef_t ClientObj(new HTTPParser(ClientFD, Namespaces)); + auto rs = Requests.size(); + auto rv = Requests.at(0).HTTPVersion; + auto rm = Requests.at(0).HTTPMethod; + auto ru = Requests.at(0).URL; + auto rh = Requests.at(0).RequestHeaders.at("Host"); + auto rp = Requests.at(0).Payload; - std::string Request("GET /test/test.png HTTP/1.1\r\nCustomHeader: one\r\n\r\n"); - ClientObj->appendBuffer(Request.c_str(), Request.length()); - auto r = ClientObj->processRequests(SHMGetRequests, ASRequestHandlerRef); + cout << "Request size: " << rs << " version: " << rv << " method: " << rm << " URL: " << ru << " Header: " << rh << " Payload: " << rp << endl; - BOOST_TEST(r == 1); + BOOST_TEST(rs == 1); + BOOST_TEST(rv == 1); + BOOST_TEST(rm == 2); + BOOST_TEST(ru == "/backend/test1"); + BOOST_TEST(rh == "test.loalnet"); + BOOST_TEST(rp == "{}"); } -BOOST_AUTO_TEST_CASE( test_multiple_get_request ) +BOOST_AUTO_TEST_CASE( test_multiple_valid_get_request_full_transmit ) { - cout << "Check multiple (2) GET requests." << endl; + cout << "Check multiple GET requests (full buffer transmit at once)." << endl; - void* SHMBase = mmap(NULL, SHMEM_STATICFS_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0); - void* SHMGetRequests = static_cast(SHMBase) + sizeof(atomic_uint16_t) + sizeof(uint16_t); + RequestsVector_t Requests; - void* SHMASMeta = mmap(NULL, SHMEM_STATICFS_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0); - void* SHMASRequests = mmap(NULL, SHMEM_STATICFS_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0); - void* SHMASResults = mmap(NULL, SHMEM_STATICFS_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0); + unique_ptr parser = make_unique(4096); - const json JSONConfig = { { "interpreters", 2 }, { "path", "/test" } }; + string full_request(HTTP_REQUEST_GET_SINGLE1); + full_request.append(HTTP_REQUEST_GET_SINGLE2); + full_request.append(HTTP_REQUEST_GET_SINGLE3); - Namespaces_t Namespaces; - NamespaceProps_t NamespaceProps; - NamespaceProps.FilesystemRef = nullptr; - NamespaceProps.JSONConfig = JSONConfig; + parser->appendBuffer(full_request.c_str(), full_request.length()); + Requests = parser->getRequests(); - Namespaces.emplace( - "test1", NamespaceProps - ); + auto rs = Requests.size(); + auto rv1 = Requests.at(0).HTTPVersion; + auto rm1 = Requests.at(0).HTTPMethod; + auto ru1 = Requests.at(0).URL; + auto rh1 = Requests.at(0).RequestHeaders.at("CustomHeader"); - ASRequestHandlerRef_t ASRequestHandlerRef = std::make_unique( - Namespaces, - BaseAdresses_t{ SHMASMeta, SHMASRequests, SHMASResults } - ); + auto rv2 = Requests.at(1).HTTPVersion; + auto rm2 = Requests.at(1).HTTPMethod; + auto ru2 = Requests.at(1).URL; + auto rh2 = Requests.at(1).RequestHeaders.at("AnotherHeader"); - ClientFD_t ClientFD = 1; - ClientRef_t ClientObj(new HTTPParser(ClientFD, Namespaces)); + auto rv3 = Requests.at(2).HTTPVersion; + auto rm3 = Requests.at(2).HTTPMethod; + auto ru3 = Requests.at(2).URL; + auto rh3 = Requests.at(2).RequestHeaders.at("ThirdHeader"); - std::string Request("GET /test/test1.png HTTP/1.1\r\nCustomHeader: one\r\n\r\nGET /test/test2.png HTTP/1.1\r\nCustomHeader: two\r\n\r\n"); - ClientObj->appendBuffer(Request.c_str(), Request.length()); - auto r = ClientObj->processRequests(SHMGetRequests, ASRequestHandlerRef); + cout << "Request size: " << rs << endl; + cout << "Request 1 version: " << rv1 << " method: " << rm1 << " URL: " << ru1 << " Header: " << rh1 << endl; + cout << "Request 2 version: " << rv2 << " method: " << rm2 << " URL: " << ru2 << " Header: " << rh2 << endl; + cout << "Request 3 version: " << rv3 << " method: " << rm3 << " URL: " << ru3 << " Header: " << rh3 << endl; + + BOOST_TEST(rs == 3); + + BOOST_TEST(rv1 == 1); + BOOST_TEST(rm1 == 1); + BOOST_TEST(ru1 == "/test/test.png"); + BOOST_TEST(rh1 == "one"); + + BOOST_TEST(rv2 == 1); + BOOST_TEST(rm2 == 1); + BOOST_TEST(ru2 == "/test/test2.png"); + BOOST_TEST(rh2 == "two"); + + BOOST_TEST(rv3 == 1); + BOOST_TEST(rm3 == 1); + BOOST_TEST(ru3 == "/test/test3.png"); + BOOST_TEST(rh3 == "three"); - BOOST_TEST(r == 2); } -BOOST_AUTO_TEST_CASE( test_single_post_as_request ) +BOOST_AUTO_TEST_CASE( test_multiple_valid_get_request_1byte_transmit ) { - cout << "Check single POST request." << endl; + cout << "Check multiple GET requests (1-byte buffer transmit)." << endl; + + RequestsVector_t Requests; + + unique_ptr parser = make_unique(4096); - void* SHMBase = mmap(NULL, SHMEM_STATICFS_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0); - void* SHMGetRequests = static_cast(SHMBase) + sizeof(atomic_uint16_t) + sizeof(uint16_t); + string full_request(HTTP_REQUEST_GET_SINGLE1); + full_request.append(HTTP_REQUEST_GET_SINGLE2); + full_request.append(HTTP_REQUEST_GET_SINGLE3); - void* SHMASMeta = mmap(NULL, SHMEM_STATICFS_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0); - void* SHMASRequests = mmap(NULL, SHMEM_STATICFS_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0); - void* SHMASResults = mmap(NULL, SHMEM_STATICFS_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0); + // Send data byte by byte + for (size_t i = 0; i < full_request.length(); i++) { + parser->appendBuffer(full_request.c_str() + i, 1); + } + Requests = parser->getRequests(); - const json JSONConfig = { { "interpreters", 2 }, { "path", "/test" } }; + auto rs = Requests.size(); + auto rv1 = Requests.at(0).HTTPVersion; + auto rm1 = Requests.at(0).HTTPMethod; + auto ru1 = Requests.at(0).URL; + auto rh1 = Requests.at(0).RequestHeaders.at("CustomHeader"); - Namespaces_t Namespaces; - NamespaceProps_t NamespaceProps; - NamespaceProps.FilesystemRef = nullptr; - NamespaceProps.JSONConfig = JSONConfig; + auto rv2 = Requests.at(1).HTTPVersion; + auto rm2 = Requests.at(1).HTTPMethod; + auto ru2 = Requests.at(1).URL; + auto rh2 = Requests.at(1).RequestHeaders.at("AnotherHeader"); - Namespaces.emplace( - "test1", NamespaceProps - ); + auto rv3 = Requests.at(2).HTTPVersion; + auto rm3 = Requests.at(2).HTTPMethod; + auto ru3 = Requests.at(2).URL; + auto rh3 = Requests.at(2).RequestHeaders.at("ThirdHeader"); - ASRequestHandlerRef_t ASRequestHandlerRef = std::make_unique( - Namespaces, - BaseAdresses_t{ SHMASMeta, SHMASRequests, SHMASResults } - ); + cout << "Request size: " << rs << endl; + cout << "Request 1 version: " << rv1 << " method: " << rm1 << " URL: " << ru1 << " Header: " << rh1 << endl; + cout << "Request 2 version: " << rv2 << " method: " << rm2 << " URL: " << ru2 << " Header: " << rh2 << endl; + cout << "Request 3 version: " << rv3 << " method: " << rm3 << " URL: " << ru3 << " Header: " << rh3 << endl; - ClientFD_t ClientFD = 1; - ClientRef_t ClientObj(new HTTPParser(ClientFD, Namespaces)); + BOOST_TEST(rs == 3); - std::string Request("POST /backend/test1 HTTP/1.1\r\nHost: test.loalnet\r\nContent-Type: application/json\r\nContent-Length: 2\r\n\r\n{}"); - ClientObj->appendBuffer(Request.c_str(), Request.length()); - auto r = ClientObj->processRequests(SHMGetRequests, ASRequestHandlerRef); + BOOST_TEST(rv1 == 1); + BOOST_TEST(rm1 == 1); + BOOST_TEST(ru1 == "/test/test.png"); + BOOST_TEST(rh1 == "one"); + + BOOST_TEST(rv2 == 1); + BOOST_TEST(rm2 == 1); + BOOST_TEST(ru2 == "/test/test2.png"); + BOOST_TEST(rh2 == "two"); + + BOOST_TEST(rv3 == 1); + BOOST_TEST(rm3 == 1); + BOOST_TEST(ru3 == "/test/test3.png"); + BOOST_TEST(rh3 == "three"); - BOOST_TEST(r == 0); } -BOOST_AUTO_TEST_CASE( test_single_get_as_request ) +BOOST_AUTO_TEST_CASE( test_multiple_valid_get_and_post_requests_full_transmit ) { - cout << "Check single GET AS request." << endl; + cout << "Check multiple GET and POST requests (full buffer transmit at once)." << endl; + + RequestsVector_t Requests; + + unique_ptr parser = make_unique(4096); + + string full_request(HTTP_REQUEST_GET_SINGLE1); + full_request.append(HTTP_REQUEST_POST_SINGLE); + full_request.append(HTTP_REQUEST_GET_SINGLE2); + full_request.append(HTTP_REQUEST_POST_SINGLE); + full_request.append(HTTP_REQUEST_GET_SINGLE3); + + parser->appendBuffer(full_request.c_str(), full_request.length()); + Requests = parser->getRequests(); - void* SHMBase = mmap(NULL, SHMEM_STATICFS_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0); - void* SHMGetRequests = static_cast(SHMBase) + sizeof(atomic_uint16_t) + sizeof(uint16_t); + auto rs = Requests.size(); + auto rv1 = Requests.at(0).HTTPVersion; + auto rm1 = Requests.at(0).HTTPMethod; + auto ru1 = Requests.at(0).URL; + auto rh1 = Requests.at(0).RequestHeaders.at("CustomHeader"); - void* SHMASMeta = mmap(NULL, SHMEM_STATICFS_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0); - void* SHMASRequests = mmap(NULL, SHMEM_STATICFS_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0); - void* SHMASResults = mmap(NULL, SHMEM_STATICFS_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0); + auto rv2 = Requests.at(1).HTTPVersion; + auto rm2 = Requests.at(1).HTTPMethod; + auto ru2 = Requests.at(1).URL; + auto rh2 = Requests.at(1).RequestHeaders.at("Content-Type"); - std::ifstream ConfigFile("./as-get.json"); - const json JSONConfig = json::parse(ConfigFile); + auto rv3 = Requests.at(2).HTTPVersion; + auto rm3 = Requests.at(2).HTTPMethod; + auto ru3 = Requests.at(2).URL; + auto rh3 = Requests.at(2).RequestHeaders.at("Host"); - Namespaces_t Namespaces; - NamespaceProps_t NamespaceProps; - NamespaceProps.FilesystemRef = nullptr; - NamespaceProps.JSONConfig = JSONConfig; + cout << "Request size: " << rs << endl; + cout << "Request 1 version: " << rv1 << " method: " << rm1 << " URL: " << ru1 << " Header: " << rh1 << endl; + cout << "Request 2 version: " << rv2 << " method: " << rm2 << " URL: " << ru2 << " Header: " << rh2 << endl; + cout << "Request 3 version: " << rv3 << " method: " << rm3 << " URL: " << ru3 << " Header: " << rh3 << endl; - Namespaces.emplace( - "test.local", NamespaceProps - ); + BOOST_TEST(rs == 5); - ASRequestHandlerRef_t ASRequestHandlerRef = std::make_unique( - Namespaces, - BaseAdresses_t{ SHMASMeta, SHMASRequests, SHMASResults } - ); + BOOST_TEST(rv1 == 1); + BOOST_TEST(rm1 == 1); + BOOST_TEST(ru1 == "/test/test.png"); + BOOST_TEST(rh1 == "one"); - ClientFD_t ClientFD = 1; - ClientRef_t ClientObj(new HTTPParser(ClientFD, Namespaces)); + BOOST_TEST(rv2 == 1); + BOOST_TEST(rm2 == 2); + BOOST_TEST(ru2 == "/backend/test1"); + BOOST_TEST(rh2 == "application/json"); - std::string Request("GET /backend/test1?param1=test1¶m2=test2 HTTP/1.1\r\nHost: test.local\r\nCustomHeader: one\r\n\r\n"); - ClientObj->appendBuffer(Request.c_str(), Request.length()); - auto r = ClientObj->processRequests(SHMGetRequests, ASRequestHandlerRef); + BOOST_TEST(rv3 == 1); + BOOST_TEST(rm3 == 1); + BOOST_TEST(ru3 == "/test/test2.png"); + BOOST_TEST(rh3 == "test.dns"); - BOOST_TEST(r == 0); } -BOOST_AUTO_TEST_CASE( test_multiple_get_request_truncated ) +BOOST_AUTO_TEST_CASE( test_multiple_valid_get_and_post_requests_1byte_transmit ) { - cout << "Check multiple (3) GET requests, truncated over 2 requests." << endl; + cout << "Check multiple GET and POST requests (1-byte buffer transmit)." << endl; + + RequestsVector_t Requests; + + unique_ptr parser = make_unique(4096); + + string full_request(HTTP_REQUEST_GET_SINGLE1); + full_request.append(HTTP_REQUEST_POST_SINGLE); + full_request.append(HTTP_REQUEST_GET_SINGLE2); + full_request.append(HTTP_REQUEST_POST_SINGLE); + full_request.append(HTTP_REQUEST_GET_SINGLE3); + + // Send data byte by byte + for (size_t i = 0; i < full_request.length(); i++) { + parser->appendBuffer(full_request.c_str() + i, 1); + } + Requests = parser->getRequests(); + + auto rs = Requests.size(); + auto rv1 = Requests.at(0).HTTPVersion; + auto rm1 = Requests.at(0).HTTPMethod; + auto ru1 = Requests.at(0).URL; + auto rh1 = Requests.at(0).RequestHeaders.at("CustomHeader"); + + auto rv2 = Requests.at(1).HTTPVersion; + auto rm2 = Requests.at(1).HTTPMethod; + auto ru2 = Requests.at(1).URL; + auto rh2 = Requests.at(1).RequestHeaders.at("Content-Type"); + + auto rv3 = Requests.at(2).HTTPVersion; + auto rm3 = Requests.at(2).HTTPMethod; + auto ru3 = Requests.at(2).URL; + auto rh3 = Requests.at(2).RequestHeaders.at("Host"); + + cout << "Request size: " << rs << endl; + cout << "Request 1 version: " << rv1 << " method: " << rm1 << " URL: " << ru1 << " Header: " << rh1 << endl; + cout << "Request 2 version: " << rv2 << " method: " << rm2 << " URL: " << ru2 << " Header: " << rh2 << endl; + cout << "Request 3 version: " << rv3 << " method: " << rm3 << " URL: " << ru3 << " Header: " << rh3 << endl; + + BOOST_TEST(rs == 5); + + BOOST_TEST(rv1 == 1); + BOOST_TEST(rm1 == 1); + BOOST_TEST(ru1 == "/test/test.png"); + BOOST_TEST(rh1 == "one"); + + BOOST_TEST(rv2 == 1); + BOOST_TEST(rm2 == 2); + BOOST_TEST(ru2 == "/backend/test1"); + BOOST_TEST(rh2 == "application/json"); + + BOOST_TEST(rv3 == 1); + BOOST_TEST(rm3 == 1); + BOOST_TEST(ru3 == "/test/test2.png"); + BOOST_TEST(rh3 == "test.dns"); - void* SHMBase = mmap(NULL, SHMEM_STATICFS_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0); - void* SHMGetRequests = static_cast(SHMBase) + sizeof(atomic_uint16_t) + sizeof(uint16_t); +} - void* SHMASMeta = mmap(NULL, SHMEM_STATICFS_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0); - void* SHMASRequests = mmap(NULL, SHMEM_STATICFS_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0); - void* SHMASResults = mmap(NULL, SHMEM_STATICFS_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0); +BOOST_AUTO_TEST_CASE( test_single_valid_post_request_partial_transmit ) +{ + cout << "Check single POST request (partial transmit)." << endl; - const json JSONConfig = { {"interpreters", 2}, {"path", "/test"} }; + RequestsVector_t Requests; - Namespaces_t Namespaces; - NamespaceProps_t NamespaceProps; - NamespaceProps.FilesystemRef = nullptr; - NamespaceProps.JSONConfig = JSONConfig; + unique_ptr parser = make_unique(4096); - Namespaces.emplace( - "test1", NamespaceProps - ); + parser->appendBuffer(HTTP_REQUEST_POST_PARTIAL1.c_str(), HTTP_REQUEST_POST_PARTIAL1.length()); + parser->appendBuffer(HTTP_REQUEST_POST_PARTIAL2.c_str(), HTTP_REQUEST_POST_PARTIAL2.length()); + parser->appendBuffer(HTTP_REQUEST_POST_PARTIAL3.c_str(), HTTP_REQUEST_POST_PARTIAL3.length()); + Requests = parser->getRequests(); - ASRequestHandlerRef_t ASRequestHandlerRef = std::make_unique( - Namespaces, - BaseAdresses_t{ SHMASMeta, SHMASRequests, SHMASResults } - ); + auto rs = Requests.size(); + auto rv = Requests.at(0).HTTPVersion; + auto rm = Requests.at(0).HTTPMethod; + auto ru = Requests.at(0).URL; + auto rh = Requests.at(0).RequestHeaders.at("Content-Type"); - ClientFD_t ClientFD = 1; - ClientRef_t ClientObj(new HTTPParser(ClientFD, Namespaces)); + cout << "Request size: " << rs << " version: " << rv << " method: " << rm << " URL: " << ru << " Header: " << rh << endl; - std::string Request("GET /t/tA.png HTTP/1.1\r\nCustomHeader: a\r\n\r\nGET /t/tB.png HTTP/1.1\r\nCustomHeader: b\r\n\r\nGET /t/tC.png HT"); - ClientObj->appendBuffer(Request.c_str(), Request.length()); - auto r1 = ClientObj->processRequests(SHMGetRequests, ASRequestHandlerRef); + BOOST_TEST(rs == 1); + BOOST_TEST(rv == 2); + BOOST_TEST(rm == 1); + BOOST_TEST(ru == "/other/path"); + BOOST_TEST(rh == "application/json"); - std::string Request2("TP/1.1\r\nCustomHeader: c\r\n\r\n"); - ClientObj->appendBuffer(Request2.c_str(), Request2.length()); - auto r2 = ClientObj->processRequests(SHMGetRequests, ASRequestHandlerRef); +} + +BOOST_AUTO_TEST_CASE( test_single_valid_post_request_partial_1byte_transmit ) +{ + cout << "Check single POST request (partial 1-byte buffer transmit)." << endl; + + RequestsVector_t Requests; + + unique_ptr parser = make_unique(4096); + + // Send each partial byte by byte + for (size_t i = 0; i < HTTP_REQUEST_POST_PARTIAL1.length(); i++) { + parser->appendBuffer(HTTP_REQUEST_POST_PARTIAL1.c_str() + i, 1); + } + for (size_t i = 0; i < HTTP_REQUEST_POST_PARTIAL2.length(); i++) { + parser->appendBuffer(HTTP_REQUEST_POST_PARTIAL2.c_str() + i, 1); + } + for (size_t i = 0; i < HTTP_REQUEST_POST_PARTIAL3.length(); i++) { + parser->appendBuffer(HTTP_REQUEST_POST_PARTIAL3.c_str() + i, 1); + } + Requests = parser->getRequests(); + + auto rs = Requests.size(); + auto rv = Requests.at(0).HTTPVersion; + auto rm = Requests.at(0).HTTPMethod; + auto ru = Requests.at(0).URL; + auto rh = Requests.at(0).RequestHeaders.at("Content-Type"); + + cout << "Request size: " << rs << " version: " << rv << " method: " << rm << " URL: " << ru << " Header: " << rh << endl; + + BOOST_TEST(rs == 1); + BOOST_TEST(rv == 2); + BOOST_TEST(rm == 1); + BOOST_TEST(ru == "/other/path"); + BOOST_TEST(rh == "application/json"); - BOOST_TEST(r1 == 2); - BOOST_TEST(r2 == 1); } diff --git a/test/unit/http-parser/test-parser-requests.cpp.old b/test/unit/http-parser/test-parser-requests.cpp.old new file mode 100644 index 0000000..3b550a2 --- /dev/null +++ b/test/unit/http-parser/test-parser-requests.cpp.old @@ -0,0 +1,201 @@ +#define BOOST_TEST_MAIN +#include +#include + +#include "../../../src/Client.hpp" +#include "../../../src/ClientHandler.hpp" + +using namespace std; +using json = nlohmann::json; + + +BOOST_AUTO_TEST_CASE( test_single_get_request ) +{ + cout << "Check single GET request." << endl; + + void* SHMBase = mmap(NULL, SHMEM_STATICFS_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0); + void* SHMGetRequests = static_cast(SHMBase) + sizeof(atomic_uint16_t) + sizeof(uint16_t); + + void* SHMASMeta = mmap(NULL, SHMEM_STATICFS_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0); + void* SHMASRequests = mmap(NULL, SHMEM_STATICFS_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0); + void* SHMASResults = mmap(NULL, SHMEM_STATICFS_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0); + + const json JSONConfig = { { "interpreters", 2 }, { "path", "/test" } }; + + Namespaces_t Namespaces; + NamespaceProps_t NamespaceProps; + NamespaceProps.FilesystemRef = nullptr; + NamespaceProps.JSONConfig = JSONConfig; + + Namespaces.emplace( + "test1", NamespaceProps + ); + + ASRequestHandlerRef_t ASRequestHandlerRef = std::make_unique( + Namespaces, + BaseAdresses_t{ SHMASMeta, SHMASRequests, SHMASResults } + ); + + ClientFD_t ClientFD = 1; + ClientRef_t ClientObj(new HTTPParser(ClientFD, Namespaces)); + + std::string Request("GET /test/test.png HTTP/1.1\r\nCustomHeader: one\r\n\r\n"); + ClientObj->appendBuffer(Request.c_str(), Request.length()); + auto r = ClientObj->processRequests(SHMGetRequests, ASRequestHandlerRef); + + BOOST_TEST(r == 1); +} + +BOOST_AUTO_TEST_CASE( test_multiple_get_request ) +{ + cout << "Check multiple (2) GET requests." << endl; + + void* SHMBase = mmap(NULL, SHMEM_STATICFS_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0); + void* SHMGetRequests = static_cast(SHMBase) + sizeof(atomic_uint16_t) + sizeof(uint16_t); + + void* SHMASMeta = mmap(NULL, SHMEM_STATICFS_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0); + void* SHMASRequests = mmap(NULL, SHMEM_STATICFS_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0); + void* SHMASResults = mmap(NULL, SHMEM_STATICFS_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0); + + const json JSONConfig = { { "interpreters", 2 }, { "path", "/test" } }; + + Namespaces_t Namespaces; + NamespaceProps_t NamespaceProps; + NamespaceProps.FilesystemRef = nullptr; + NamespaceProps.JSONConfig = JSONConfig; + + Namespaces.emplace( + "test1", NamespaceProps + ); + + ASRequestHandlerRef_t ASRequestHandlerRef = std::make_unique( + Namespaces, + BaseAdresses_t{ SHMASMeta, SHMASRequests, SHMASResults } + ); + + ClientFD_t ClientFD = 1; + ClientRef_t ClientObj(new HTTPParser(ClientFD, Namespaces)); + + std::string Request("GET /test/test1.png HTTP/1.1\r\nCustomHeader: one\r\n\r\nGET /test/test2.png HTTP/1.1\r\nCustomHeader: two\r\n\r\n"); + ClientObj->appendBuffer(Request.c_str(), Request.length()); + auto r = ClientObj->processRequests(SHMGetRequests, ASRequestHandlerRef); + + BOOST_TEST(r == 2); +} + +BOOST_AUTO_TEST_CASE( test_single_post_as_request ) +{ + cout << "Check single POST request." << endl; + + void* SHMBase = mmap(NULL, SHMEM_STATICFS_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0); + void* SHMGetRequests = static_cast(SHMBase) + sizeof(atomic_uint16_t) + sizeof(uint16_t); + + void* SHMASMeta = mmap(NULL, SHMEM_STATICFS_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0); + void* SHMASRequests = mmap(NULL, SHMEM_STATICFS_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0); + void* SHMASResults = mmap(NULL, SHMEM_STATICFS_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0); + + const json JSONConfig = { { "interpreters", 2 }, { "path", "/test" } }; + + Namespaces_t Namespaces; + NamespaceProps_t NamespaceProps; + NamespaceProps.FilesystemRef = nullptr; + NamespaceProps.JSONConfig = JSONConfig; + + Namespaces.emplace( + "test1", NamespaceProps + ); + + ASRequestHandlerRef_t ASRequestHandlerRef = std::make_unique( + Namespaces, + BaseAdresses_t{ SHMASMeta, SHMASRequests, SHMASResults } + ); + + ClientFD_t ClientFD = 1; + ClientRef_t ClientObj(new HTTPParser(ClientFD, Namespaces)); + + std::string Request("POST /backend/test1 HTTP/1.1\r\nHost: test.loalnet\r\nContent-Type: application/json\r\nContent-Length: 2\r\n\r\n{}"); + ClientObj->appendBuffer(Request.c_str(), Request.length()); + auto r = ClientObj->processRequests(SHMGetRequests, ASRequestHandlerRef); + + BOOST_TEST(r == 0); +} + +BOOST_AUTO_TEST_CASE( test_single_get_as_request ) +{ + cout << "Check single GET AS request." << endl; + + void* SHMBase = mmap(NULL, SHMEM_STATICFS_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0); + void* SHMGetRequests = static_cast(SHMBase) + sizeof(atomic_uint16_t) + sizeof(uint16_t); + + void* SHMASMeta = mmap(NULL, SHMEM_STATICFS_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0); + void* SHMASRequests = mmap(NULL, SHMEM_STATICFS_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0); + void* SHMASResults = mmap(NULL, SHMEM_STATICFS_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0); + + std::ifstream ConfigFile("./as-get.json"); + const json JSONConfig = json::parse(ConfigFile); + + Namespaces_t Namespaces; + NamespaceProps_t NamespaceProps; + NamespaceProps.FilesystemRef = nullptr; + NamespaceProps.JSONConfig = JSONConfig; + + Namespaces.emplace( + "test.local", NamespaceProps + ); + + ASRequestHandlerRef_t ASRequestHandlerRef = std::make_unique( + Namespaces, + BaseAdresses_t{ SHMASMeta, SHMASRequests, SHMASResults } + ); + + ClientFD_t ClientFD = 1; + ClientRef_t ClientObj(new HTTPParser(ClientFD, Namespaces)); + + std::string Request("GET /backend/test1?param1=test1¶m2=test2 HTTP/1.1\r\nHost: test.local\r\nCustomHeader: one\r\n\r\n"); + ClientObj->appendBuffer(Request.c_str(), Request.length()); + auto r = ClientObj->processRequests(SHMGetRequests, ASRequestHandlerRef); + + BOOST_TEST(r == 0); +} + +BOOST_AUTO_TEST_CASE( test_multiple_get_request_truncated ) +{ + cout << "Check multiple (3) GET requests, truncated over 2 requests." << endl; + + void* SHMBase = mmap(NULL, SHMEM_STATICFS_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0); + void* SHMGetRequests = static_cast(SHMBase) + sizeof(atomic_uint16_t) + sizeof(uint16_t); + + void* SHMASMeta = mmap(NULL, SHMEM_STATICFS_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0); + void* SHMASRequests = mmap(NULL, SHMEM_STATICFS_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0); + void* SHMASResults = mmap(NULL, SHMEM_STATICFS_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0); + + const json JSONConfig = { {"interpreters", 2}, {"path", "/test"} }; + + Namespaces_t Namespaces; + NamespaceProps_t NamespaceProps; + NamespaceProps.FilesystemRef = nullptr; + NamespaceProps.JSONConfig = JSONConfig; + + Namespaces.emplace( + "test1", NamespaceProps + ); + + ASRequestHandlerRef_t ASRequestHandlerRef = std::make_unique( + Namespaces, + BaseAdresses_t{ SHMASMeta, SHMASRequests, SHMASResults } + ); + + ClientFD_t ClientFD = 1; + ClientRef_t ClientObj(new HTTPParser(ClientFD, Namespaces)); + + std::string Request("GET /t/tA.png HTTP/1.1\r\nCustomHeader: a\r\n\r\nGET /t/tB.png HTTP/1.1\r\nCustomHeader: b\r\n\r\nGET /t/tC.png HT"); + ClientObj->appendBuffer(Request.c_str(), Request.length()); + auto r1 = ClientObj->processRequests(SHMGetRequests, ASRequestHandlerRef); + + std::string Request2("TP/1.1\r\nCustomHeader: c\r\n\r\n"); + ClientObj->appendBuffer(Request2.c_str(), Request2.length()); + auto r2 = ClientObj->processRequests(SHMGetRequests, ASRequestHandlerRef); + + BOOST_TEST(r1 == 2); + BOOST_TEST(r2 == 1); +}