#include "../test.h"
#define TEST(name) TEST_CASE("parse-request: " name, "[parse-request]")
TEST("get") {
RequestParser p;
string raw =
"GET / HTTP/1.0\r\n"
"Host: host1\r\n"
"\r\n";
auto result = p.parse(raw);
auto req = result.request;
CHECK(result.state == State::done);
CHECK(req->method_raw() == Method::Get);
CHECK(req->http_version == 10);
CHECK(req->uri->to_string() == "/");
}
TEST("post") {
RequestParser p;
string raw =
"POST /upload HTTP/1.1\r\n"
"Content-Length: 23\r\n"
"\r\n"
"Wikipedia in\r\n\r\nchunks."
;
auto result = p.parse(raw);
auto req = result.request;
CHECK(result.state == State::done);
CHECK(req->method_raw() == Method::Post);
CHECK(req->http_version == 11);
CHECK(req->uri->to_string() == "/upload");
}
TEST("request without length") {
RequestParser p;
string body = GENERATE(string(""), string("1"));
string raw =
"GET / HTTP/1.1\r\n"
"Host: host1\r\n"
"\r\n" + body;
auto result = p.parse(raw);
auto req = result.request;
CHECK(result.state == State::done);
CHECK(req->http_version == 11);
CHECK_FALSE(req->body.length());
}
TEST("fragmented method") {
RequestParser p;
string v[] = {
"G", "ET / HTTP/1", ".0\r\n"
"Header1: header1\r\n"
"\r\n"
};
RequestParser::Result result;
for (auto s : v) {
if (result.request) CHECK(result.state != State::done);
result = p.parse(s);
}
auto req = result.request;
CHECK(result.state == State::done);
CHECK(req->method_raw() == Method::Get);
CHECK(req->http_version == 10);
CHECK(req->headers.get("Header1") == "header1");
}
TEST("parsing request byte by byte") {
RequestParser p;
string s =
"GET /uri HTTP/1.0\r\n"
"Header1: header1\r\n"
"Header2: header2\r\n"
"\r\n";
const size_t CHUNK = GENERATE(1, 10);
RequestParser::Result result;
while (s) {
if (result.request) CHECK(result.state != State::done);
result = p.parse(s.substr(0, CHUNK));
s.offset(CHUNK < s.length() ? CHUNK : s.length());
}
auto req = result.request;
CHECK(result.state == State::done);
CHECK(req->method_raw() == Method::Get);
CHECK(req->http_version == 10);
CHECK(req->headers.get("Header1") == "header1");
CHECK(req->headers.get("Header2") == "header2");
}
TEST("double first line") {
RequestParser p;
string raw =
"GET / HTTP/1.0\r\n"
"GET / HTTP/1.0\r\n"
"Host: host1\r\n"
"\r\n";
auto result = p.parse(raw);
auto req = result.request;
CHECK(result.error);
CHECK(req->method_raw() == Method::Get);
CHECK(req->http_version == 10);
}
TEST("bad first line") {
RequestParser p;
string raw =
"\r\n"
"GET / HTTP/1.0\r\n"
"Host: host1\r\n"
"\r\n";
CHECK(p.parse(raw).error);
}
TEST("protocol-relative url parsed as path") {
RequestParser p;
string raw = "GET //my///path?a=b HTTP/1.0\r\n\r\n";
auto result = p.parse(raw);
auto req = result.request;
CHECK(result.state == State::done);
CHECK(req->uri->to_string() == "//my///path?a=b");
CHECK(req->uri->path() == "//my///path");
p.reset();
raw ="GET ///my//path?a=b HTTP/1.0\r\n\r\n";
result = p.parse(raw);
req = result.request;
CHECK(result.state == State::done);
CHECK(req->uri->to_string() == "///my//path?a=b");
CHECK(req->uri->path() == "///my//path");
}
TEST("uses allow_extended_chars for uri") {
RequestParser p;
string raw =
"GET /?a=b|c HTTP/1.0\r\n"
"Host: host1\r\n"
"\r\n";
auto result = p.parse(raw);
auto req = result.request;
CHECK(result.state == State::done);
CHECK(req->uri->to_string() == "/?a=b%7Cc");
}