Skip to content

Commit

Permalink
feat: add query and fragment parsing to HttpRequestParser (#766)
Browse files Browse the repository at this point in the history
* feat: add query and fragment parsing to HttpRequestParser

* Add more tests
  • Loading branch information
richardapeters authored Nov 8, 2024
1 parent e110c4d commit 644934b
Show file tree
Hide file tree
Showing 4 changed files with 84 additions and 3 deletions.
29 changes: 27 additions & 2 deletions services/network/HttpRequestParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,23 @@ namespace services

void HttpRequestParserImpl::FindPath(infra::Tokenizer& tokenizer)
{
path = tokenizer.Token(1);
pathTokens = infra::Tokenizer(path, '/');
auto url = tokenizer.Token(1);

auto fragmentStart = url.find('#');
if (fragmentStart != infra::BoundedConstString::npos)
{
fragment = url.substr(fragmentStart + 1);
url = url.substr(0, fragmentStart);
}

auto queryStart = url.find('?');
if (queryStart != infra::BoundedConstString::npos)
{
query = url.substr(queryStart + 1);
url = url.substr(0, queryStart);
}

pathTokens = infra::Tokenizer(url, '/');
}

bool HttpRequestParserImpl::HeadersComplete() const
Expand All @@ -50,6 +65,16 @@ namespace services
return pathTokens;
}

infra::BoundedConstString HttpRequestParserImpl::Query() const
{
return query;
}

infra::BoundedConstString HttpRequestParserImpl::Fragment() const
{
return fragment;
}

infra::BoundedConstString HttpRequestParserImpl::Header(infra::BoundedConstString name) const
{
auto headersTail = headers;
Expand Down
7 changes: 6 additions & 1 deletion services/network/HttpRequestParser.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ namespace services
virtual bool Valid() const = 0;
virtual HttpVerb Verb() const = 0;
virtual const infra::Tokenizer& PathTokens() const = 0;
virtual infra::BoundedConstString Query() const = 0;
virtual infra::BoundedConstString Fragment() const = 0;
virtual infra::BoundedConstString Header(infra::BoundedConstString name) const = 0;
virtual void EnumerateHeaders(const infra::Function<void(infra::BoundedConstString name, infra::BoundedConstString value)>& enumerator) const = 0;
virtual infra::BoundedString& BodyBuffer() = 0;
Expand All @@ -37,6 +39,8 @@ namespace services
bool Valid() const override;
HttpVerb Verb() const override;
const infra::Tokenizer& PathTokens() const override;
infra::BoundedConstString Query() const override;
infra::BoundedConstString Fragment() const override;
infra::BoundedConstString Header(infra::BoundedConstString name) const override;
void EnumerateHeaders(const infra::Function<void(infra::BoundedConstString name, infra::BoundedConstString value)>& enumerator) const override;
infra::BoundedString& BodyBuffer() override;
Expand All @@ -54,7 +58,8 @@ namespace services
infra::BoundedString headers;
infra::BoundedString bodyBuffer;
HttpVerb verb;
infra::BoundedConstString path;
infra::BoundedConstString query;
infra::BoundedConstString fragment;
infra::Tokenizer pathTokens;
bool headersComplete = true;
bool valid = true;
Expand Down
39 changes: 39 additions & 0 deletions services/network/test/TestHttpServer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,45 @@
#include "services/network/test_doubles/HttpServerMock.hpp"
#include "gmock/gmock.h"

TEST(HttpRequestParserTest, parser_elements)
{
infra::BoundedString::WithStorage<256> request("GET a/b?query#fragment HTTP1.1\r\nkey: value\r\n\r\nbody");
services::HttpRequestParserImpl parser(request);

EXPECT_EQ(services::HttpVerb::get, parser.Verb());
EXPECT_EQ("a", parser.PathTokens().Token(0));
EXPECT_EQ("b", parser.PathTokens().Token(1));
EXPECT_EQ("value", parser.Header("key"));
EXPECT_EQ("query", parser.Query());
EXPECT_EQ("fragment", parser.Fragment());
}

TEST(HttpRequestParserTest, parser_elements_without_query)
{
infra::BoundedString::WithStorage<256> request("GET a/b#fragment HTTP1.1\r\nkey: value\r\n\r\nbody");
services::HttpRequestParserImpl parser(request);

EXPECT_EQ(services::HttpVerb::get, parser.Verb());
EXPECT_EQ("a", parser.PathTokens().Token(0));
EXPECT_EQ("b", parser.PathTokens().Token(1));
EXPECT_EQ("value", parser.Header("key"));
EXPECT_EQ("", parser.Query());
EXPECT_EQ("fragment", parser.Fragment());
}

TEST(HttpRequestParserTest, parser_elements_without_fragment)
{
infra::BoundedString::WithStorage<256> request("GET a/b?query HTTP1.1\r\nkey: value\r\n\r\nbody");
services::HttpRequestParserImpl parser(request);

EXPECT_EQ(services::HttpVerb::get, parser.Verb());
EXPECT_EQ("a", parser.PathTokens().Token(0));
EXPECT_EQ("b", parser.PathTokens().Token(1));
EXPECT_EQ("value", parser.Header("key"));
EXPECT_EQ("query", parser.Query());
EXPECT_EQ("", parser.Fragment());
}

class HttpServerTest
: public testing::Test
, public infra::ClockFixture
Expand Down
12 changes: 12 additions & 0 deletions services/network/test_doubles/HttpRequestParserStub.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,16 @@ namespace services
return pathTokens;
}

infra::BoundedConstString Query() const override
{
return query;
}

infra::BoundedConstString Fragment() const override
{
return fragment;
}

infra::BoundedConstString Header(infra::BoundedConstString name) const override
{
for (auto& header : headers)
Expand Down Expand Up @@ -75,6 +85,8 @@ namespace services

HttpVerb verb;
infra::BoundedConstString path;
infra::BoundedConstString query;
infra::BoundedConstString fragment;
infra::Tokenizer pathTokens;
infra::BoundedString::WithStorage<1024> body;
uint32_t contentLength;
Expand Down

0 comments on commit 644934b

Please sign in to comment.