24#include <boost/network/protocol/http/client.hpp>
25#include <catch2/catch.hpp>
34namespace http = boost::network::http;
39 bool isEnvironmentInitialized =
false;
43 unique_ptr<RequestHandler> httpRequestHandler;
49 bool initializeEnvironmentIfNotYetDone() {
50 if (isEnvironmentInitialized) {
56 {{
"http",
"reuseaddr"},
"on"},
57 {{
"post",
"max_size"},
"1"},
58 {{
"system",
"request_handler"},
"http"},
59 {{
"logging",
"level"},
"debug"},
60 {{
"logging",
"extended"},
"on"},
63 port = config[{
"http",
"port"}].empty() ?
"8080" : config[{
"http",
"port"}];
64 baseUrl =
"http://127.0.0.1:" + port;
67 httpRequestHandler = RequestHandler::newRequestHandler([](
Connection&) {
return 0; }, config, 1));
69 isEnvironmentInitialized =
true;
74TEST_CASE(
"Basic request handling (HTTP)",
"[basic][http]") {
75 REQUIRE(initializeEnvironmentIfNotYetDone());
77 auto& requestHandler = httpRequestHandler;
79 auto handlingFunction = [](
Connection& connection) ->
int {
80 connection.responseStream() <<
"Hello World!";
84 requestHandler->reconfigure(make_shared<HandleRequestFunctionWrapper>(handlingFunction), nullopt, config));
85 REQUIRE_NOTHROW(requestHandler->start());
88 http::client::request request(baseUrl);
89 http::client::response response;
90 REQUIRE_NOTHROW(response = client.get(request));
91 CHECK(response.body() ==
"Hello World!");
94TEST_CASE(
"Environment and headers (HTTP)",
"[headers][http]") {
95 REQUIRE(initializeEnvironmentIfNotYetDone());
96 auto& requestHandler = httpRequestHandler;
98 auto handlingFunction = [](
Connection& connection) ->
int {
99 auto& resp = connection.responseStream();
100 auto& env = connection.request().env();
102 resp << env.getRequestPath().size() <<
"\n";
103 resp << env[
"REMOTE_ADDR"] <<
"\n";
104 resp << env[
"REQUEST_URI"] <<
"\n";
105 resp << env[
"REMOTE_PORT"] <<
"\n";
106 resp << env[
"REQUEST_METHOD"] <<
"\n";
107 resp << env[
"SERVER_ADDR"] <<
"\n";
108 resp << env[
"SERVER_PORT"] <<
"\n";
109 resp << env[
"SERVER_SOFTWARE"] <<
"\n";
110 resp << env[
"BASE_URL"] <<
"\n";
111 resp << env[
"FULL_URL_WITH_QS"] <<
"\n";
112 resp << env[
"FULL_URL_WITHOUT_QS"] <<
"\n";
113 resp << env[
"host"] <<
"\n";
114 resp << env[
"content-type"] <<
"\n";
117 connection.setHeader(
"x-test-header",
"test");
118 connection.setHeader(
"x-second-test",
"test");
119 connection.unsetHeader(
"x-second-test");
123 requestHandler->reconfigure(make_shared<HandleRequestFunctionWrapper>(handlingFunction), nullopt, config));
124 REQUIRE_NOTHROW(requestHandler->start());
127 http::client::response response;
129 auto checkResponse = [&](
string const& method) {
131 REQUIRE(respLines.size() == 13);
132 CHECK(respLines[0] ==
"3");
133 CHECK(respLines[1] ==
"127.0.0.1");
134 CHECK(respLines[2] ==
"/tp0/tp1/test?qse0=v0&qse1=v1");
135 CHECK(respLines[4] == method);
136 CHECK(respLines[5] ==
"127.0.0.1");
137 CHECK(respLines[6] == port);
138 CHECK(respLines[8] == baseUrl);
139 CHECK(respLines[9] == baseUrl +
"/tp0/tp1/test?qse0=v0&qse1=v1");
140 CHECK(respLines[10] == baseUrl +
"/tp0/tp1/test");
141 CHECK(respLines[11] ==
"127.0.0.1:" + port);
143 REQUIRE(response.headers().count(
"x-test-header") == 1);
144 CHECK(response.headers().equal_range(
"x-test-header").first->second ==
"test");
145 CHECK(response.headers().count(
"x-second-test") == 0);
148 SECTION(
"GET request") {
149 http::client::request request(baseUrl +
"/tp0/tp1/test?qse0=v0&qse1=v1");
150 REQUIRE_NOTHROW(response = client.get(request));
151 checkResponse(
"GET");
154 SECTION(
"POST request") {
155 http::client::request request(baseUrl +
"/tp0/tp1/test?qse0=v0&qse1=v1");
156 REQUIRE_NOTHROW(response = client.post(request));
157 checkResponse(
"POST");
162 REQUIRE(initializeEnvironmentIfNotYetDone());
163 auto& requestHandler = httpRequestHandler;
165 auto handlingFunction = [](
Connection& connection) ->
int {
166 auto& resp = connection.responseStream();
167 auto& env = connection.request().env();
168 auto& session = connection.session();
171 if (!session.isSet(
"testKey")) {
173 session.set(
"testKey",
"testVal");
176 resp << any_cast<string>(session[
"testKey"]);
177 }
catch (bad_any_cast
const&) {
186 requestHandler->reconfigure(make_shared<HandleRequestFunctionWrapper>(handlingFunction), nullopt, config));
187 REQUIRE_NOTHROW(requestHandler->start());
190 http::client::response response;
192 http::client::request request(baseUrl);
193 REQUIRE_NOTHROW(response = client.get(request));
194 CHECK(response.body() ==
"not set");
195 auto cookieIterator = response.headers().find(
"Set-Cookie");
196 REQUIRE(cookieIterator != response.headers().end());
198 auto parsedCookieIt = parsedCookie.find(
"SESSION");
199 REQUIRE(parsedCookieIt != parsedCookie.end());
200 string sessionId = parsedCookieIt->second;
202 request << boost::network::header(
"Cookie",
"SESSION=" + sessionId);
203 REQUIRE_NOTHROW(response = client.get(request));
204 CHECK(response.body() ==
"testVal");
Response object to be passed back to NAWA and accessor to the request.
Exception class that can be used by apps to catch errors resulting from nawa function calls.
Handles and serves incoming requests via the NAWA app.
void insert(std::initializer_list< std::pair< std::pair< std::string, std::string >, std::string > > init)
TEST_CASE("Basic request handling (HTTP)", "[basic][http]")
std::vector< std::string > splitString(std::string str, char delimiter, bool ignoreEmpty=false)
std::unordered_multimap< std::string, std::string > parseCookies(std::string const &rawCookies)
Contains useful functions that improve the readability and facilitate maintenance of the NAWA code.