Added some HTTP parser unit tests, fixed HTTP support for zero content length, added gcovr file for coverage reports
This commit is contained in:
parent
9a599a06de
commit
8b8a28c4ec
5 changed files with 89 additions and 3 deletions
3
gcovr.cfg
Normal file
3
gcovr.cfg
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
filter = src/
|
||||||
|
filter = lib/
|
||||||
|
|
|
@ -45,6 +45,7 @@ void HTTP::Parser::CleanPreserveHeaders(){
|
||||||
protocol = "HTTP/1.1";
|
protocol = "HTTP/1.1";
|
||||||
body.clear();
|
body.clear();
|
||||||
length = 0;
|
length = 0;
|
||||||
|
knownLength = false;
|
||||||
vars.clear();
|
vars.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -619,11 +620,13 @@ bool HTTP::Parser::parse(std::string &HTTPbuffer, Util::DataCallback &cb){
|
||||||
if (tmpA.size() == 0){
|
if (tmpA.size() == 0){
|
||||||
seenHeaders = true;
|
seenHeaders = true;
|
||||||
body.clear();
|
body.clear();
|
||||||
|
knownLength = false;
|
||||||
if (GetHeader("Content-Length") != ""){
|
if (GetHeader("Content-Length") != ""){
|
||||||
length = atoi(GetHeader("Content-Length").c_str());
|
length = atoi(GetHeader("Content-Length").c_str());
|
||||||
if (!bodyCallback && (&cb == &Util::defaultDataCallback) && body.capacity() < length){
|
if (!bodyCallback && (&cb == &Util::defaultDataCallback) && body.capacity() < length){
|
||||||
body.reserve(length);
|
body.reserve(length);
|
||||||
}
|
}
|
||||||
|
knownLength = true;
|
||||||
}
|
}
|
||||||
if (GetHeader("Transfer-Encoding") == "chunked"){
|
if (GetHeader("Transfer-Encoding") == "chunked"){
|
||||||
getChunks = true;
|
getChunks = true;
|
||||||
|
@ -645,7 +648,7 @@ bool HTTP::Parser::parse(std::string &HTTPbuffer, Util::DataCallback &cb){
|
||||||
unsigned int code = atoi(url.data());
|
unsigned int code = atoi(url.data());
|
||||||
if ((code >= 100 && code < 200) || code == 204 || code == 304){return true;}
|
if ((code >= 100 && code < 200) || code == 204 || code == 304){return true;}
|
||||||
}
|
}
|
||||||
if (length > 0 && !getChunks){
|
if (knownLength && !getChunks){
|
||||||
unsigned int toappend = length - body.length();
|
unsigned int toappend = length - body.length();
|
||||||
|
|
||||||
// limit the amount of bytes that will be appended to the amount there
|
// limit the amount of bytes that will be appended to the amount there
|
||||||
|
@ -673,8 +676,8 @@ bool HTTP::Parser::parse(std::string &HTTPbuffer, Util::DataCallback &cb){
|
||||||
currentLength += toappend;
|
currentLength += toappend;
|
||||||
}
|
}
|
||||||
if (length == body.length()){
|
if (length == body.length()){
|
||||||
// parse POST variables
|
// parse POST body if the content type is URLEncoded
|
||||||
if (method == "POST"){parseVars(body, vars);}
|
if (method == "POST" && GetHeader("Content-Type") == "application/x-www-form-urlencoded"){parseVars(body, vars);}
|
||||||
return true;
|
return true;
|
||||||
}else{
|
}else{
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -57,6 +57,7 @@ namespace HTTP{
|
||||||
std::string url;
|
std::string url;
|
||||||
std::string protocol;
|
std::string protocol;
|
||||||
unsigned int length;
|
unsigned int length;
|
||||||
|
bool knownLength;
|
||||||
unsigned int currentLength;
|
unsigned int currentLength;
|
||||||
bool headerOnly; ///< If true, do not parse body if the length is a known size.
|
bool headerOnly; ///< If true, do not parse body if the length is a known size.
|
||||||
bool bufferChunks;
|
bool bufferChunks;
|
||||||
|
|
64
test/http_parser.cpp
Normal file
64
test/http_parser.cpp
Normal file
|
@ -0,0 +1,64 @@
|
||||||
|
#include <iostream>
|
||||||
|
#include <mist/http_parser.h>
|
||||||
|
#include <mist/timing.h>
|
||||||
|
|
||||||
|
int main(int argc, char ** argv){
|
||||||
|
bool preMade = false;
|
||||||
|
Socket::Connection C(1, 0); // Open stdio by default
|
||||||
|
// If there is a T_HTTP environment variable, use that as input instead
|
||||||
|
if (getenv("T_HTTP")){
|
||||||
|
preMade = true;
|
||||||
|
// Keep stdio open, only drop the reference to it
|
||||||
|
C.drop();
|
||||||
|
// Create a pipe and reconnect the socket to it
|
||||||
|
int p[2];
|
||||||
|
if (pipe(p)){
|
||||||
|
FAIL_MSG("Could not open pipe!");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
C.open(p[1], p[0]);
|
||||||
|
// Write the T_HTTP env contents into the pipe
|
||||||
|
C.SendNow(getenv("T_HTTP"));
|
||||||
|
// Close the write end if we're not lingering
|
||||||
|
if (!getenv("T_LINGER")){close(p[1]);}
|
||||||
|
}
|
||||||
|
|
||||||
|
HTTP::Parser p;
|
||||||
|
int counter = 0;
|
||||||
|
C.setBlocking(false);
|
||||||
|
uint64_t lastData = Util::bootMS();
|
||||||
|
do {
|
||||||
|
if (C.spool()){
|
||||||
|
lastData = Util::bootMS();
|
||||||
|
while (p.Read(C)){
|
||||||
|
INFO_MSG("Read a HTTP message: %s %s %s (%zu bytes)", p.method.c_str(), p.url.c_str(), p.protocol.c_str(), p.body.size());
|
||||||
|
++counter;
|
||||||
|
p.Clean();
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
// premade requests will instantly time out, others after 10 seconds
|
||||||
|
if (preMade){break;}
|
||||||
|
if (Util::bootMS() > lastData + 10000){
|
||||||
|
WARN_MSG("Read timeout, aborting");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
Util::sleep(5);
|
||||||
|
}
|
||||||
|
}while(C);
|
||||||
|
while (p.Read(C)){
|
||||||
|
INFO_MSG("Read a HTTP message: %s %s %s (%zu bytes)", p.method.c_str(), p.url.c_str(), p.protocol.c_str(), p.body.size());
|
||||||
|
++counter;
|
||||||
|
p.Clean();
|
||||||
|
}
|
||||||
|
|
||||||
|
INFO_MSG("Total messages: %d", counter);
|
||||||
|
|
||||||
|
if (getenv("T_COUNT")){
|
||||||
|
if (counter != atoi(getenv("T_COUNT"))){
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
|
@ -148,6 +148,21 @@ test('DTSC Sizing Test', dtsc_sizing_test)
|
||||||
bitwritertest = executable('bitwritertest', 'bitwriter.cpp', dependencies: libmist_dep)
|
bitwritertest = executable('bitwritertest', 'bitwriter.cpp', dependencies: libmist_dep)
|
||||||
test('bitWriter Test', bitwritertest)
|
test('bitWriter Test', bitwritertest)
|
||||||
|
|
||||||
|
httpparsertest = executable('httpparsertest', 'http_parser.cpp', dependencies: libmist_dep)
|
||||||
|
test('GET request for /', httpparsertest, suite: 'HTTP parser', env: {'T_HTTP':'GET / HTTP/1.1\n\n', 'T_COUNT':'1'})
|
||||||
|
test('GET request for / with carriage returns', httpparsertest, suite: 'HTTP parser', env: {'T_HTTP':'GET / HTTP/1.1\r\n\r\n', 'T_COUNT':'1'})
|
||||||
|
test('POST request to /, raw body', httpparsertest, suite: 'HTTP parser', env: {'T_HTTP':'POST / HTTP/1.1\nContent-Length: 4\nContent-Type: text/plain\n\ntest', 'T_COUNT':'1'})
|
||||||
|
test('POST request to /, urlencoded body', httpparsertest, suite: 'HTTP parser', env: {'T_HTTP':'POST / HTTP/1.1\nContent-Length: 28\nContent-Type: application/x-www-form-urlencoded\n\nfoo=bar&banana=sauce&cookies', 'T_COUNT':'1'})
|
||||||
|
test('Blank HTTP response, closed connection', httpparsertest, suite: 'HTTP parser', env: {'T_HTTP':'HTTP/1.1 200 OK\nDate: Thu, 15 Jun 2023 21:34:06 GMT\nContent-Length: 0\n\n', 'T_COUNT':'1'})
|
||||||
|
test('Blank HTTP response, lingering connection', httpparsertest, suite: 'HTTP parser', env: {'T_HTTP':'HTTP/1.1 200 OK\nDate: Thu, 15 Jun 2023 21:34:06 GMT\nContent-Length: 0\n\n', 'T_LINGER':'1', 'T_COUNT':'1'})
|
||||||
|
test('Simple HTTP response, closed connection', httpparsertest, suite: 'HTTP parser', env: {'T_HTTP':'HTTP/1.1 200 OK\nDate: Thu, 15 Jun 2023 21:34:06 GMT\nContent-Length: 4\n\ntest', 'T_COUNT':'1'})
|
||||||
|
test('Simple HTTP response, lingering connection', httpparsertest, suite: 'HTTP parser', env: {'T_HTTP':'HTTP/1.1 200 OK\nDate: Thu, 15 Jun 2023 21:34:06 GMT\nContent-Length: 4\n\ntest', 'T_LINGER':'1', 'T_COUNT':'1'})
|
||||||
|
test('Simple HTTP response, no length, closed connection', httpparsertest, suite: 'HTTP parser', env: {'T_HTTP':'HTTP/1.1 200 OK\nDate: Thu, 15 Jun 2023 21:34:06 GMT\n\ntest', 'T_COUNT':'1'})
|
||||||
|
test('Simple HTTP response, no length, lingering connection', httpparsertest, suite: 'HTTP parser', env: {'T_HTTP':'HTTP/1.1 200 OK\nDate: Thu, 15 Jun 2023 21:34:06 GMT\n\ntest', 'T_LINGER':'1', 'T_COUNT':'0'})
|
||||||
|
test('Chunked HTTP response, closed connection', httpparsertest, suite: 'HTTP parser', env: {'T_HTTP':'HTTP/1.1 200 OK\nTransfer-Encoding: chunked\n\n1\nt\n3\nest\n0\n\n', 'T_COUNT':'1'})
|
||||||
|
test('Chunked HTTP response, lingering connection', httpparsertest, suite: 'HTTP parser', env: {'T_HTTP':'HTTP/1.1 200 OK\nTransfer-Encoding: chunked\n\n1\nt\n3\nest\n0\n\n', 'T_LINGER':'1', 'T_COUNT':'1'})
|
||||||
|
|
||||||
|
|
||||||
#abst_test = executable('abst_test', 'abst_test.cpp', dependencies: libmist_dep)
|
#abst_test = executable('abst_test', 'abst_test.cpp', dependencies: libmist_dep)
|
||||||
#test('MP4::ABST Test', abst_test)
|
#test('MP4::ABST Test', abst_test)
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue