Skip to content

Verify HTTP server overload responds with HTTP 503 - #2436

Open
riemass wants to merge 2 commits into
mainfrom
topic/riemass/http-test
Open

Verify HTTP server overload responds with HTTP 503#2436
riemass wants to merge 2 commits into
mainfrom
topic/riemass/http-test

Conversation

@riemass

@riemass riemass commented Jun 27, 2026

Copy link
Copy Markdown
Member

Followup to #2236.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a regression test to ensure CAF’s HTTP server responds with HTTP 503 when its request queue is overloaded (follow-up to #2236), while still allowing already-queued requests to complete normally.

Changes:

  • Introduces low-level HTTP response parsing helper(s) to validate raw responses from a socket pair.
  • Adds a new test that overloads the request queue via HTTP pipelining and verifies overflow requests get HTTP 503 while queued requests later return HTTP 200.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread libcaf_net/caf/net/http/with.test.cpp Outdated
@codecov

codecov Bot commented Jun 27, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 73.11%. Comparing base (79de8ae) to head (fdce0db).

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #2436      +/-   ##
==========================================
+ Coverage   72.95%   73.11%   +0.15%     
==========================================
  Files         642      642              
  Lines       30702    30718      +16     
  Branches     3362     3364       +2     
==========================================
+ Hits        22400    22460      +60     
+ Misses       6371     6323      -48     
- Partials     1931     1935       +4     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@riemass
riemass force-pushed the topic/riemass/http-test branch from ad18d1d to df4a351 Compare June 29, 2026 08:45

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 1 out of 1 changed files in this pull request and generated 2 comments.

Comment on lines +463 to +466
request_buffer->close();
net::http::request dummy;
require_eq(consumer.pull(async::delay_errors, dummy, 1s),
async::read_result::stop);

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will cause an ASAN memory leak described in #2437.

Comment thread libcaf_net/caf/net/http/with.test.cpp Outdated
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
@riemass
riemass requested a review from Neverlord June 29, 2026 09:34

using latch_ptr = std::shared_ptr<std::latch>;

struct raw_http_response {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's raw about this? It has already been parsed.

Comment on lines +102 to +103
raw_header.push_back(
static_cast<char>(std::to_integer<unsigned char>(buf[0])));

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
raw_header.push_back(
static_cast<char>(std::to_integer<unsigned char>(buf[0])));
raw_header.push_back(std::to_integer<char>(buf[0]));

Comment on lines +96 to +97
byte_buffer buf;
buf.resize(1);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
byte_buffer buf;
buf.resize(1);

buf.resize(1);
while (raw_header.find("\r\n\r\n") == std::string::npos) {
require_readable();
auto bytes_read = net::read(fd, buf);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't need a heap-allocated buffer for a single byte.

Suggested change
auto bytes_read = net::read(fd, buf);
auto buf = std::byte{};
auto bytes_read = net::read(fd, std::span{&buf, 1});

while (raw_header.find("\r\n\r\n") == std::string::npos) {
require_readable();
auto bytes_read = net::read(fd, buf);
self.require_eq(bytes_read, ptrdiff_t{1}, loc);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
self.require_eq(bytes_read, ptrdiff_t{1}, loc);
self.require_eq(bytes_read, 1, loc);

raw_http_response result;
auto parse_result = result.header.parse(raw_header);
self.require_eq(parse_result.first, net::http::status::ok, loc);
auto content_length = result.header.content_length().value_or(size_t{0});

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
auto content_length = result.header.content_length().value_or(size_t{0});
auto content_length = result.header.content_length().value_or(0u);

check_eq(elog->errors(), std::vector<error>{});
}

SCENARIO("server responds with 503 unavailable when queue is overloaded") {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
SCENARIO("server responds with 503 unavailable when queue is overloaded") {
SCENARIO("a server responds with status 503 on queue overloads") {

auto overflow_count = size_t{2};
auto [server_fd, client_fd] = unbox(net::make_stream_socket_pair());
net::socket_guard client_guard{client_fd};
std::optional<async::consumer_resource<net::http::request>> requests;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The resource has a default constructor, can be assigned and has a valid() method. No need to wrap this into an optional.

Suggested change
std::optional<async::consumer_resource<net::http::request>> requests;
async::consumer_resource<net::http::request> requests;

Comment on lines +435 to +450
// Fill the queue, and send two requests that overflow the queue.
for (auto i = size_t{0}; i < request_count; ++i) {
auto req = detail::format("GET /{} HTTP/1.1\r\nHost: localhost\r\n\r\n",
i);
require_eq(net::write(client_fd, as_bytes(std::span{req})),
static_cast<ptrdiff_t>(req.size()));
}
THEN("the two overflow requests receive 503 responses") {
for (auto i = size_t{0}; i < overflow_count; ++i) {
auto response = read_http_response(client_fd);
check_eq(response.header.status(), uint16_t{503});
check_eq(response.header.status_text(), "Service Unavailable");
check_eq(response.body,
"service unavailable: request could not be queued");
}
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Am I reading this wrong? We are writing n+2 requests. The last two should overflow. And then the server is sending the errors first?

Isn't all of this using the same socket? The server must process the requests in order. How else can the client match responses to requests? So I would expect n times a valid response and then 2 errors. Per connection, the server cannot start processing a new request before it has replied to the most recent one.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants