Skip to content

fix(Net): reactor-based http server not response when requests with body #5227

Merged
matejk merged 7 commits intopocoproject:mainfrom
sky92zwq:fix/reactor-http
Mar 15, 2026
Merged

fix(Net): reactor-based http server not response when requests with body #5227
matejk merged 7 commits intopocoproject:mainfrom
sky92zwq:fix/reactor-http

Conversation

@sky92zwq
Copy link
Copy Markdown
Contributor

Some problems fixed PR :

  1. not response when requests with body
  2. the reactor server can't quit with CTRL + C correctly.
  3. fix redefination of HTTPReactorServer.h

@sky92zwq sky92zwq changed the title ix(Net): reactor-based http server not response for requests with body fix(Net): reactor-based http server not response for requests with body Feb 25, 2026
@sky92zwq sky92zwq changed the title fix(Net): reactor-based http server not response for requests with body fix(Net): reactor-based http server not response when requests with body Feb 25, 2026
Copy link
Copy Markdown
Contributor

@matejk matejk left a comment

Choose a reason for hiding this comment

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

Comprehensive Review

The PR fixes three real bugs:

  1. Body readingread() override is needed and the approach is correct
  2. CTRL+C hang_stopped guard + worker reactor stop in destructor fixes the shutdown hang
  3. Include guard — correct, follows POCO convention

However, there are several issues to address: a missing newline at EOF, code style violations (POCO uses Allman brace style), an incomplete shutdown sequence, and a questionable use of chunked encoding for empty error responses. See inline comments for details.

Missing test coverage

There is no test that exercises the body-reading path (e.g., a POST request with body via the reactor server). The only test change adds reactor->stop() to an existing test. A dedicated test for body reading would significantly increase confidence in the fix.

worker->stop();
}
if(_threadPool) {
_threadPool->joinAll();
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.

Suggested change
_threadPool->joinAll();
void TCPReactorAcceptor::stop()
{
for (auto& worker : _wokerReactors)
{
worker->stop();
}
if (_threadPool)
{
_threadPool->joinAll();
}
}

Code style: POCO uses Allman brace style (opening brace on its own line) and requires a space before ( in control statements (for (, if (). The current code uses K&R/attached style which is inconsistent with the rest of the codebase.

Also, stop() is not idempotent — it can be called explicitly and then again from the destructor. Consider adding an std::atomic<bool> _stopped guard (like TCPReactorServer does) for consistency and safety.


void TCPReactorServer::stop()
{
if (_stopped.exchange(true))
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.

The _stopped guard is good and fixes the CTRL+C double-stop issue.

However, stop() only stops the main acceptor reactors — the worker reactors inside each TCPReactorAcceptor are only stopped later when the acceptors are destroyed in the TCPReactorServer destructor. Between stop() returning and destruction, worker threads are still running. Consider also stopping acceptors explicitly:

Suggested change
if (_stopped.exchange(true))
if (_stopped.exchange(true))
{
return;
}
for (auto& acceptor : _acceptors)
{
acceptor->stop();
}

This ensures all threads (both acceptor and worker) are fully stopped when stop() returns, rather than relying on eventual destructor cleanup.

};


class BodyEchoRequestHandler: public HTTPRequestHandler
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.

Nit: the empty constructor body can be replaced with = default:

Suggested change
class BodyEchoRequestHandler: public HTTPRequestHandler
class BodyEchoRequestHandler: public HTTPRequestHandler
/// Echo the request body back to the client.
{
public:
BodyEchoRequestHandler() = default;

@matejk
Copy link
Copy Markdown
Contributor

matejk commented Mar 3, 2026

@sky92zwq, can you take a look at the code review comments?

IMO it makes sense merging this PR into next patch release.

@matejk matejk added this to the Release 1.15.1 milestone Mar 3, 2026
@matejk matejk added the bug label Mar 3, 2026
@sky92zwq
Copy link
Copy Markdown
Contributor Author

@sky92zwq, can you take a look at the code review comments?

IMO it makes sense merging this PR into next patch release.

@matejk OK. I’ve been quite busy these past two weeks, but I’ll try to address the review comments over the weekend. I’m also working on optimizing performance for a large number of concurrent connections.

@matejk
Copy link
Copy Markdown
Contributor

matejk commented Mar 13, 2026

@sky92zwq

Release for 1.15.1 is planned for next week. Shall we merge this PR and put performance optimisations to 1.15.2 or even 1.16?

@sky92zwq
Copy link
Copy Markdown
Contributor Author

@sky92zwq

Release for 1.15.1 is planned for next week. Shall we merge this PR and put performance optimisations to 1.15.2 or even 1.16?

SGTM. Merging this now and handling the performance optimizations later makes sense.

Copy link
Copy Markdown
Contributor

@matejk matejk left a comment

Choose a reason for hiding this comment

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

Thanks for addressing most of the feedback! Most issues are now fixed. Three remaining items below.

std::shared_ptr<ThreadPool> _threadPool;
RecvMessageCallback _recvMessageCallback;
TCPServerParams::Ptr _pParams;
std::atomic<bool> _stopped;
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.

Bug: _stopped is not initialized. std::atomic<bool> has a trivial default constructor that leaves the value indeterminate in C++17 and earlier. If _stopped happens to start as true, stop() will return immediately without stopping anything.

Should be:

Suggested change
std::atomic<bool> _stopped;
std::atomic<bool> _stopped{false};

(Note: TCPReactorServer correctly initializes _stopped(false) in its constructor initializer list, but TCPReactorAcceptor does not.)

stop();
}

void TCPReactorAcceptor::stop() {
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.

Minor style nits still remaining:

  1. Function definition brace should be on its own line (Allman style)
  2. Missing space before ( in for( (line 43) and if( (line 47)
Suggested change
void TCPReactorAcceptor::stop() {
void TCPReactorAcceptor::stop()
{

_reactors(pParams->getAcceptorNum()),
_pParams(pParams),
_port(port)
: _threadPool("TCPRA", pParams->getAcceptorNum()),
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.

The initializer list indentation changed from tab-indented (POCO convention) to no indentation:

// Before (POCO style)
\t: _threadPool(...),
\t  _reactors(...),
// Now
: _threadPool(...),
  _reactors(...),

This is inconsistent with the rest of the codebase. The same applies to HTTPReactorServer.cpp.

@matejk matejk merged commit 009a71f into pocoproject:main Mar 15, 2026
48 checks passed
matejk pushed a commit that referenced this pull request Mar 15, 2026
…ody (#5227)

* fix: reactor-based http server, send error when exp,  recv req body

* add POST interface in reactor server

* fix: exit stuck

* fix: reactor-based http server redefination

* fix: tsan about socket reactor testConcurrentHandlerRemoval

* address review, add unit tests

* initialize _stopped, and coding style
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants