@@ -2256,3 +2256,62 @@ BOOST_AUTO_TEST_CASE(ligo_udp_multithreaded_io_context_round_trip_succeeds) {
|
||||
BOOST_REQUIRE(message);
|
||||
BOOST_CHECK(message->payload.as_object().at("ok").as_bool());
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(ligo_response_metadata_is_preserved_by_router) {
|
||||
auto io = boost::asio::io_context{};
|
||||
auto router = ligo::service_router{};
|
||||
router.add_response_route("GET", "/metadata", [](ligo::request_context context, boost::json::value) -> boost::asio::awaitable<std::expected<ligo::service_response, modulus::error>> {
|
||||
BOOST_CHECK_EQUAL(context.headers.at("cookie"), "session=example");
|
||||
BOOST_CHECK_EQUAL(context.query.at("search"), "two words");
|
||||
auto response = ligo::text_response("text/plain", "accepted");
|
||||
response.status = 201;
|
||||
response.headers.emplace_back("Set-Cookie", "session=replacement; HttpOnly");
|
||||
response.headers.emplace_back("Cache-Control", "no-store");
|
||||
co_return response;
|
||||
});
|
||||
auto future = boost::asio::co_spawn(io, router.call_response({.method = "GET", .route = "/metadata", .headers = {{"cookie", "session=example"}}, .query = {{"search", "two words"}}}, {}), boost::asio::use_future);
|
||||
io.run();
|
||||
auto result = future.get();
|
||||
BOOST_REQUIRE(result);
|
||||
BOOST_CHECK_EQUAL(result->status, 201);
|
||||
BOOST_CHECK_EQUAL(result->body, "accepted");
|
||||
BOOST_CHECK_EQUAL(result->headers.size(), 2);
|
||||
// The old aggregate initialization remains valid.
|
||||
auto options = ligo::http::server_options{std::chrono::milliseconds{1000}, 1024, {}, ligo::security_config{}};
|
||||
BOOST_CHECK(!options.parse_query);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(ligo_http_raw_exchange_headers_query_and_status) {
|
||||
auto io = boost::asio::io_context{};
|
||||
auto router = ligo::service_router{};
|
||||
router.add_response_route("GET", "/raw", [](ligo::request_context context, boost::json::value) -> boost::asio::awaitable<std::expected<ligo::service_response, modulus::error>> {
|
||||
BOOST_CHECK_EQUAL(context.headers.at("if-none-match"), "revision-one");
|
||||
BOOST_CHECK_EQUAL(context.query.at("search"), "two words+");
|
||||
auto response = ligo::text_response("text/plain", "not a JSON envelope");
|
||||
response.status = 202;
|
||||
response.headers = {{"ETag", "revision-two"}, {"Set-Cookie", "sample=value; HttpOnly"}};
|
||||
co_return response;
|
||||
});
|
||||
auto options = ligo::http::server_options{};
|
||||
options.parse_query = true;
|
||||
auto server = ligo::http::server{io, {"127.0.0.1", 0}, std::move(router), options};
|
||||
BOOST_REQUIRE(server.start());
|
||||
auto exercise = [&]() -> boost::asio::awaitable<void> {
|
||||
auto client = ligo::http::client{{"127.0.0.1", server.selected_port()}};
|
||||
auto result = co_await client.exchange({.method = ligo::http::method::GET, .target = "/raw?search=two+words%2B", .headers = {{"If-None-Match", "revision-one"}}});
|
||||
BOOST_REQUIRE(result);
|
||||
BOOST_CHECK_EQUAL(result->status, 202);
|
||||
BOOST_CHECK_EQUAL(result->body, "not a JSON envelope");
|
||||
BOOST_CHECK_EQUAL(result->headers.at("etag"), "revision-two");
|
||||
auto invalid = co_await client.exchange({.method = ligo::http::method::GET, .target = "/raw?search=%ZZ"});
|
||||
BOOST_REQUIRE(invalid);
|
||||
BOOST_CHECK_EQUAL(invalid->status, 400);
|
||||
auto duplicate = co_await client.exchange({.method = ligo::http::method::GET, .target = "/raw?x=1&x=2"});
|
||||
BOOST_REQUIRE(duplicate);
|
||||
BOOST_CHECK_EQUAL(duplicate->status, 400);
|
||||
server.stop();
|
||||
};
|
||||
auto future = boost::asio::co_spawn(io, exercise(), boost::asio::use_future);
|
||||
io.run();
|
||||
future.get();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user