Skip to content

Commit

Permalink
fix web server crash when connection with pending requests is closed (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
pablohoch authored Nov 6, 2024
1 parent 7b089e0 commit 0c26d84
Showing 1 changed file with 38 additions and 21 deletions.
59 changes: 38 additions & 21 deletions src/web_server/http_session.cc
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ struct http_session {
};

explicit queue(http_session& self, std::size_t limit)
: self_(self), limit_(limit) {
: session_(self), limit_(limit) {
items_.reserve(limit);
}

Expand All @@ -75,13 +75,13 @@ struct http_session {
if (items_.empty() || !items_.front()->is_finished()) {
return false;
}
self_.write_active_ = true;
session_.write_active_ = true;
items_.front()->response_->send();
return true;
}

struct pending_request {
explicit pending_request(http_session& session) : self_(session) {}
explicit pending_request(http_session& session) : session_{session} {}

bool is_finished() const { return static_cast<bool>(response_); }

Expand All @@ -91,40 +91,49 @@ struct http_session {
boost::beast::http::message<IsRequest, Body, Fields>&& msg) {
// This holds a work item
struct response_impl : response {
http_session& self_;
boost::beast::http::message<IsRequest, Body, Fields> msg_;

response_impl(
http_session& self,
std::shared_ptr<http_session> session,
boost::beast::http::message<IsRequest, Body, Fields>&& msg)
: self_(self), msg_(std::move(msg)) {}
: session_(std::move(session)), msg_(std::move(msg)) {}

void send() override {
if (session_->closed_) {
return;
}
boost::beast::http::async_write(
self_.derived().stream(), msg_,
boost::beast::bind_front_handler(
&http_session::on_write, self_.derived().shared_from_this(),
msg_.need_eof()));
session_->derived().stream(), msg_,
boost::beast::bind_front_handler(&http_session::on_write,
session_, msg_.need_eof()));
}

std::shared_ptr<http_session> session_;
boost::beast::http::message<IsRequest, Body, Fields> msg_;
};

response_ = std::make_unique<response_impl>(self_, std::move(msg));
boost::asio::post(self_.derived().stream().get_executor(),
[&, self = self_.derived().shared_from_this()]() {
self_.send_next_response();
if (session_.closed_) {
return;
}
auto session = session_.derived().shared_from_this();
response_ = std::make_unique<response_impl>(session, std::move(msg));
boost::asio::post(session_.derived().stream().get_executor(),
[session]() {
if (session->closed_) {
return;
}
session->send_next_response();
});
}

http_session& self_;
http_session& session_;
std::unique_ptr<response> response_;
};

pending_request& add_entry() {
return *items_.emplace_back(std::make_unique<pending_request>(self_))
return *items_.emplace_back(std::make_unique<pending_request>(session_))
.get();
}

http_session& self_;
http_session& session_;
std::vector<std::unique_ptr<pending_request>> items_;
// Maximum number of responses we will queue
std::size_t limit_;
Expand Down Expand Up @@ -165,6 +174,7 @@ struct http_session {
}

if (ec) {
closed_ = true;
return fail(ec, "read");
}

Expand Down Expand Up @@ -212,6 +222,7 @@ struct http_session {

write_active_ = false;
if (ec) {
closed_ = true;
return fail(ec, "write");
}

Expand All @@ -237,6 +248,7 @@ struct http_session {

queue queue_;
bool write_active_{false};
bool closed_{false};

boost::beast::flat_buffer buffer_;

Expand Down Expand Up @@ -270,6 +282,7 @@ struct plain_http_session

// Called by the base class
void do_eof() {
closed_ = true;
// Send a TCP shutdown
boost::beast::error_code ec;
stream_.socket().shutdown(boost::asio::ip::tcp::socket::shutdown_send, ec);
Expand Down Expand Up @@ -332,18 +345,21 @@ struct ssl_http_session

// Called by the base class
void do_eof() {
closed_ = true;
// Set the timeout.
boost::beast::get_lowest_layer(stream_).expires_after(settings_->timeout_);

// Perform the SSL shutdown
stream_.async_shutdown(ssl_http_session::on_shutdown);
stream_.async_shutdown(boost::beast::bind_front_handler(
&ssl_http_session::on_shutdown, shared_from_this()));
}

static bool is_ssl() { return true; }

private:
void on_handshake(boost::beast::error_code ec, std::size_t bytes_used) {
if (ec) {
closed_ = true;
return fail(ec, "handshake");
}

Expand All @@ -353,8 +369,9 @@ struct ssl_http_session
do_read();
}

static void on_shutdown(boost::beast::error_code ec) {
void on_shutdown(boost::beast::error_code ec) {
if (ec) {
closed_ = true;
return fail(ec, "shutdown");
}

Expand Down

0 comments on commit 0c26d84

Please sign in to comment.