Skip to content

Commit 9613956

Browse files
authored
Merge pull request #106 from WEBcodeX1/fix-http-parser
Fix global http-parsing (libhttp)
2 parents 9045ced + 49477f3 commit 9613956

File tree

8 files changed

+236
-110
lines changed

8 files changed

+236
-110
lines changed

ClientHandler.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ void ClientHandler::readClientData(const uint16_t FDCount)
122122
ClientRef_t ClientRef = Clients.at(ReadFD);
123123
ClientRef->appendBuffer(Buffer, RcvBytes);
124124

125-
if (ClientRef->parseRequestsBasic(SHMGetRequests, _ASRequestHandlerRef) > 0) {
125+
if (ClientRef->processRequests(SHMGetRequests, _ASRequestHandlerRef) > 0) {
126126
++ProcessedClients;
127127
}
128128
}

ThreadHandler.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ void ClientThread::startThread()
126126

127127
void ClientThread::processRequests()
128128
{
129-
for (auto i=0; i<_ClientRequests.size(); ++i) {
129+
for (unsigned long i=0; i<_ClientRequests.size(); ++i) {
130130

131131
if (_ClientRequests[i].ASIndex == -1)
132132
{
@@ -135,14 +135,14 @@ void ClientThread::processRequests()
135135

136136
DBG(80, "Processing Request inside Thread with Index:'" << i << "' StartNanoseconds:" << StartNanoseconds.tv_nsec);
137137
BasePropsResult_t BaseProps;
138-
_parseBasePropsRV(_ClientRequests[i].HTTPPayload, BaseProps);
138+
_parseRequestProperties(_ClientRequests[i].HTTPPayload, BaseProps);
139139

140140
DBG(120, "RequestType:'" << BaseProps.at(2) << "'");
141141
DBG(120, "RequestPath:'" << BaseProps.at(1) << "'");
142142
DBG(120, "HTTPVersion:'" << BaseProps.at(0) << "'");
143143

144144
RequestHeaderResult_t Headers;
145-
_parseHeadersRV(_ClientRequests[i].HTTPPayload, Headers);
145+
_parseRequestHeaders(_ClientRequests[i].HTTPPayload, Headers);
146146

147147
const string NamespaceID = Headers.at("Host");
148148
DBG(120, "NamespaceID:'" << NamespaceID << "'");

lib/http/CMakeLists.txt

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,12 @@ aux_source_directory(. SRC_LIST_LIBHTTP)
88
add_library(libhttp STATIC ${SRC_LIST_LIBHTTP})
99

1010
# add lib parser and network
11-
add_custom_target(libhttpheader SOURCES ./httpparser.hpp ./httpnet.hpp)
11+
add_custom_target(
12+
libhttpheader
13+
SOURCES
14+
./httpparser.hpp
15+
./httpnet.hpp
16+
)
1217

1318
# set target link libraries
1419
target_link_libraries(libhttp ${Boost_LIBRARIES})

lib/http/httpparser.cpp

Lines changed: 70 additions & 91 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,10 @@ using namespace std;
66
HTTPParser::HTTPParser(ClientFD_t ClientFD) :
77
Client(ClientFD),
88
_RequestCount(0),
9-
_HTTPRequest(""),
10-
_RegexContentLength(regex(".*Content-Length: ([0-9]+).*", regex::extended))
9+
_RequestCountGet(0),
10+
_RequestCountPost(0),
11+
_RequestCountPostAS(0),
12+
_HTTPRequest("")
1113
{
1214
DBG(120, "Constructor");
1315
}
@@ -19,127 +21,100 @@ HTTPParser::~HTTPParser()
1921

2022
void HTTPParser::appendBuffer(const char* BufferRef, const uint16_t BufferSize)
2123
{
22-
_HTTPRequest = _HTTPRequest + std::string(&BufferRef[0], BufferSize);
24+
_HTTPRequest = _HTTPRequest + string(&BufferRef[0], BufferSize);
2325
DBG(250, "Buffer:'" << _HTTPRequest << "'");
2426
_splitRequests();
2527
}
2628

2729
void HTTPParser::_splitRequests()
2830
{
29-
DBG(200, "splitRequests Buffer:'" << _HTTPRequest << "'");
31+
DBG(180, "splitRequests Buffer:'" << _HTTPRequest << "'");
3032

31-
_SplittedRequests.clear();
32-
33-
size_t ContentLengthFoundPos = _HTTPRequest.find("Content-Length");
34-
size_t EndMarkerFoundPos = _HTTPRequest.find("\n\r");
35-
36-
cmatch RegexMatch;
37-
38-
uint SplitPosition = 0;
33+
//-> reset incomplete request string
34+
string incompleteRequest("");
3935

40-
while(
41-
(ContentLengthFoundPos < EndMarkerFoundPos) ||
42-
(ContentLengthFoundPos == string::npos && EndMarkerFoundPos != string::npos)
43-
)
44-
{
45-
if (ContentLengthFoundPos < EndMarkerFoundPos) {
46-
if (regex_match(_HTTPRequest.c_str(), RegexMatch, _RegexContentLength)) {
47-
DBG(140, "Content-Length header found.");
48-
int ContentLength = stoi(RegexMatch[1]);
49-
SplitPosition = EndMarkerFoundPos+ContentLength+3;
50-
}
51-
}
52-
else if (ContentLengthFoundPos == string::npos && EndMarkerFoundPos != string::npos)
53-
{
54-
SplitPosition = EndMarkerFoundPos+3;
55-
}
36+
//-> cut from last found \n\r (last valid request end marker) until string end
37+
size_t LastDelimiterPos = _HTTPRequest.rfind("\n\r");
5638

57-
_SplittedRequests.push_back(
58-
_HTTPRequest.substr(0, SplitPosition)
59-
);
39+
//-> if min 1 full valid request && rest without end marker
40+
if (LastDelimiterPos != string::npos && LastDelimiterPos != _HTTPRequest.length()) {
6041

61-
_HTTPRequest.erase(0, SplitPosition);
42+
//-> put incomplete last request into tmp string
43+
incompleteRequest = _HTTPRequest.substr(LastDelimiterPos);
6244

63-
ContentLengthFoundPos = _HTTPRequest.find("Content-Length");
64-
EndMarkerFoundPos = _HTTPRequest.find("\n\r");
45+
//-> remove "\n\r"
46+
incompleteRequest.replace(0, 2, "");
6547
}
6648

49+
//-> split requests into _SplittedRequests vector
50+
_SplittedRequests.clear();
51+
String::split(_HTTPRequest, "\n\r", _SplittedRequests);
6752
_RequestCount = _SplittedRequests.size();
68-
DBG(120, "splitRequests after split Vector Element count:" << _RequestCount);
69-
}
53+
DBG(120, "splitRequests count after splitted into Vector:" << _RequestCount);
7054

71-
void HTTPParser::parseRequestsComplete()
72-
{
73-
for (auto &Request:_SplittedRequests) {
74-
vector<std::string> RequestLines;
75-
String::split(Request, "\n", RequestLines);
76-
}
55+
//-> "restore" incomplete last request buffer
56+
_HTTPRequest = incompleteRequest;
7757
}
7858

79-
uint HTTPParser::parseRequestsBasic(SharedMemAddress_t SHMGetRequests, const ASRequestHandlerRef_t ASRequestHandlerRef)
59+
uint HTTPParser::processRequests(SharedMemAddress_t SHMGetRequests, const ASRequestHandlerRef_t ASRequestHandlerRef)
8060
{
8161
setBaseAddress(SHMGetRequests);
8262

83-
uint16_t PythonRequestCount = 0;
84-
8563
for (auto &Request:_SplittedRequests) {
86-
PythonRequestCount += _parseBaseProps(Request, ASRequestHandlerRef);
64+
_processRequestProperties(Request, ASRequestHandlerRef);
8765
}
8866

89-
return _SplittedRequests.size() - PythonRequestCount;
67+
return _RequestCountGet;
9068
}
9169

92-
uint16_t HTTPParser::_parseBaseProps(string& Request, const ASRequestHandlerRef_t ASRequestHandlerRef)
70+
void HTTPParser::_processRequestProperties(string& Request, const ASRequestHandlerRef_t ASRequestHandlerRef)
9371
{
9472
DBG(180, "HTTP Request:'" << Request << "'");
9573

96-
//- find first line endline
97-
size_t StartPos = Request.find("\n");
98-
99-
//- set result vector
100-
vector<std::string> BasePropsFound;
101-
102-
//- reverse split
103-
String::rsplit(Request, StartPos, " ", BasePropsFound);
74+
BasePropsResult_t BasePropsFound;
75+
this->_parseRequestProperties(Request, BasePropsFound);
10476

10577
DBG(140, "HTTP Version:" << BasePropsFound.at(0) << " File:" << BasePropsFound.at(1) << " Method:" << BasePropsFound.at(2));
10678
DBG(140, "HTTP Payload (c_str):" << Request.c_str());
10779

108-
uint16_t HTTPMethod = (BasePropsFound.at(2).find("POST") != string::npos) ? 2 : 1;
109-
uint16_t HTTPVersion = (BasePropsFound.at(0).find("HTTP/1.1") != string::npos) ? 1 : 2;
80+
//- check HTTP/1.2 (currently unimplemented)
81+
const size_t HTTPVersion1_2Found = BasePropsFound.at(0).find("HTTP/1.2");
82+
83+
//- if not HTTP/1.1, do not process further
84+
const size_t HTTPVersion1_1Found = BasePropsFound.at(0).find("HTTP/1.1");
85+
86+
const uint16_t HTTPMethod = (BasePropsFound.at(2).find("POST") != string::npos) ? 2 : 1;
87+
const uint16_t HTTPVersion = (BasePropsFound.at(0).find("HTTP/1.1") != string::npos) ? 1 : 2;
11088

111-
size_t PythonReqFound = BasePropsFound.at(1).find("/python/");
89+
//- check if POST request is an AS request
90+
const size_t PythonReqFound = BasePropsFound.at(1).find("/python/");
11291

92+
//- get unique request nr
11393
uint16_t RequestNr = getNextReqNr();
11494

115-
DBG(140, "HTTP RequestNr:" << RequestNr << " HTTPVersion:" << HTTPVersion);
95+
DBG(140, "HTTP RequestNr:" << RequestNr << " HTTPVersion:" << HTTPVersion << " HTTPMethod:" << HTTPMethod);
11696

117-
cmatch RegexMatch;
97+
if (HTTPMethod == 2) {
98+
++this->_RequestCountPost;
99+
}
118100

119-
if (PythonReqFound != BasePropsFound.at(1).npos) {
101+
if (HTTPMethod == 2 && PythonReqFound != BasePropsFound.at(1).npos) {
120102

121103
DBG(140, "Python Request:" << Request);
122104

123-
string Payload = "";
124-
125-
size_t ContentLengthFoundPos = Request.find("Content-Length");
126-
size_t EndMarkerFoundPos = Request.find("\n\r");
105+
++this->_RequestCountPostAS;
127106

128-
if (ContentLengthFoundPos != string::npos && EndMarkerFoundPos != string::npos) {
129-
if (regex_match(Request.c_str(), RegexMatch, _RegexContentLength)) {
130-
DBG(140, "Content-Length header found.");
131-
int ContentLength = stoi(RegexMatch[1]);
132-
uint SubStrStart = EndMarkerFoundPos+3;
133-
uint SubStrEnd = EndMarkerFoundPos+ContentLength+3;
134-
Payload = Request.substr(SubStrStart, SubStrEnd);
135-
}
136-
}
107+
//-> cut first properties line from request
108+
size_t FirstLineEndMarker = Request.find("\n");
109+
Request.replace(0, FirstLineEndMarker+1, "");
137110

138-
//- get Host header
139-
BasePropsResult_t BaseProps;
140111
RequestHeaderResult_t Headers;
141-
this->_parseBasePropsRV(Request, BaseProps);
142-
this->_parseHeadersRV(Request, Headers);
112+
this->_parseRequestHeaders(Request, Headers);
113+
114+
auto ContentBytes = stoi(Headers.at("Content-Length"));
115+
string Payload = Request.substr(Request.length()-ContentBytes, ContentBytes);
116+
117+
DBG(140, "HTTP POST-AS payload:" << Payload);
143118

144119
//- add ASRequestHandler request
145120
ASRequestHandlerRef->addRequest({
@@ -150,9 +125,12 @@ uint16_t HTTPParser::_parseBaseProps(string& Request, const ASRequestHandlerRef_
150125
RequestNr,
151126
Payload
152127
});
153-
return 1;
154128
}
155-
else {
129+
130+
if (HTTPMethod == 1) {
131+
132+
++this->_RequestCountGet;
133+
156134
//- set values in get requests shared memory
157135
const char* MsgCString = Request.c_str();
158136

@@ -173,32 +151,33 @@ uint16_t HTTPParser::_parseBaseProps(string& Request, const ASRequestHandlerRef_
173151

174152
void* NextSegmentAddr = getNextAddress(MsgLength);
175153
DBG(120, "Set SharedMem ClientFD:" << ClientFDAddr << " PayloadLength:" << MsgLengthAddr << " Payload:" << MsgAddress << " NextSegment:" << NextSegmentAddr);
176-
return 0;
177154
}
178155
}
179156

180-
void HTTPParser::_parseBasePropsRV(string& Request, BasePropsResultRef_t ResultRef)
157+
void HTTPParser::_parseRequestProperties(string& Request, BasePropsResultRef_t ResultRef)
181158
{
182159
DBG(120, "HTTP Request:'" << Request << "'");
183160

184161
//- find first line endline
185162
size_t StartPos = Request.find("\n");
186163

164+
//-> if no headers (no \n), set start pos to end of string
165+
if (StartPos == string::npos) {
166+
StartPos = Request.length();
167+
}
168+
187169
//- reverse split
188170
String::rsplit(Request, StartPos, " ", ResultRef);
189171

190-
//- remove first line from Request
191-
Request = Request.substr(StartPos+1, Request.length());
192-
193172
DBG(120, "HTTP Version:" << ResultRef.at(0) << " File:" << ResultRef.at(1) << " Method:" << ResultRef.at(2) << " Request:" << Request);
194173
}
195174

196-
void HTTPParser::_parseHeadersRV(string& Request, RequestHeaderResultRef_t ResultRef)
175+
void HTTPParser::_parseRequestHeaders(string& Request, RequestHeaderResultRef_t ResultRef)
197176
{
198177
DBG(120, "HTTP Request:'" << Request << "'");
199178

200179
//- reverse split header lines
201-
vector<std::string> Lines;
180+
vector<string> Lines;
202181
String::split(Request, "\n", Lines);
203182

204183
//- loop over lines, split, put into result map
@@ -208,12 +187,12 @@ void HTTPParser::_parseHeadersRV(string& Request, RequestHeaderResultRef_t Resul
208187

209188
DBG(120, "Line:'" << Line << "'");
210189

211-
vector<std::string> HeaderPair;
190+
vector<string> HeaderPair;
212191
if (Line.find(':') != string::npos) {
213192
String::rsplit(Line, Line.length(), ": ", HeaderPair);
214193

215-
std::string HeaderID = HeaderPair.at(1);
216-
std::string HeaderValue = HeaderPair.at(0).substr(0, HeaderPair.at(0).length()-1);
194+
string HeaderID = HeaderPair.at(1);
195+
string HeaderValue = HeaderPair.at(0).substr(0, HeaderPair.at(0).length());
217196

218197
DBG(120, "HeaderID:'" << HeaderID << "'");
219198
DBG(120, "HeaderValue:'" << HeaderValue << "'");

lib/http/httpparser.hpp

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,5 @@
11
#ifndef LibHTTP_parser_hpp
22
#define LibHTTP_parser_hpp
3-
4-
#include <boost/regex.hpp>
5-
63
#include "../../Debug.cpp"
74
#include "../../Helper.hpp"
85
#include "../../IPCHandler.hpp"
@@ -11,7 +8,6 @@
118
#include "../../Client.hpp"
129

1310
#include <string>
14-
#include <regex>
1511

1612
typedef pair<string, string> HeaderPair_t;
1713
typedef unordered_map<string, string> RequestHeader_t;
@@ -26,9 +22,14 @@ typedef BasePropsResult_t& BasePropsResultRef_t;
2622
static const vector<string> HeaderList
2723
{
2824
"Host",
29-
"Request-UUID"
25+
"Request-UUID",
26+
"Transfer-Encoding",
3027
"User-Agent",
28+
"Accept",
29+
"Accept-Encoding",
3130
"ETag",
31+
"Cache-Control",
32+
"Content-Type",
3233
"Content-Length"
3334
};
3435

@@ -42,26 +43,27 @@ class HTTPParser: private Client, private SHMStaticFS, private SHMPythonAS
4243
~HTTPParser();
4344

4445
void appendBuffer(const char*, const uint16_t);
45-
uint parseRequestsBasic(SharedMemAddress_t, const ASRequestHandlerRef_t);
46-
void parseRequestsComplete();
46+
uint processRequests(SharedMemAddress_t, const ASRequestHandlerRef_t);
4747

4848
private:
4949

5050
void _splitRequests();
51-
void _parseRequestHeader();
52-
uint16_t _parseBaseProps(string&, const ASRequestHandlerRef_t);
51+
void _processRequestProperties(string&, const ASRequestHandlerRef_t);
5352

5453
RequestHeader_t _RequestHeaders;
5554
vector<string> _SplittedRequests;
5655

5756
size_t _RequestCount;
57+
size_t _RequestCountGet;
58+
size_t _RequestCountPost;
59+
size_t _RequestCountPostAS;
60+
5861
string _HTTPRequest;
59-
regex _RegexContentLength;
6062

6163
protected:
6264

63-
void _parseBasePropsRV(string&, BasePropsResultRef_t);
64-
void _parseHeadersRV(string&, RequestHeaderResultRef_t);
65+
void _parseRequestProperties(string&, BasePropsResultRef_t);
66+
void _parseRequestHeaders(string&, RequestHeaderResultRef_t);
6567

6668
};
6769

test/unit/CMakeLists.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
# add source dir
2-
aux_source_directory(. SRC_LIST_TEST_UNIT)
1+
# add subdirs
2+
add_subdirectory(http-parser)

0 commit comments

Comments
 (0)