forked from boostorg/beast
http write returns success on connection close (API Change):
fix #767 The write family of HTTP stream algorithms no longer returns error::end_of_stream when the message indicates that the connection should be closed. Actions Required: * Add code to servers to close the connection after successfully writing a message where `message::keep_alive()` would return `false`.
This commit is contained in:
@@ -248,7 +248,8 @@ class session : public std::enable_shared_from_this<session>
|
||||
&session::on_write,
|
||||
self_.shared_from_this(),
|
||||
std::placeholders::_1,
|
||||
std::placeholders::_2)));
|
||||
std::placeholders::_2,
|
||||
! sp->keep_alive())));
|
||||
}
|
||||
};
|
||||
|
||||
@@ -331,20 +332,21 @@ public:
|
||||
void
|
||||
on_write(
|
||||
boost::system::error_code ec,
|
||||
std::size_t bytes_transferred)
|
||||
std::size_t bytes_transferred,
|
||||
bool close)
|
||||
{
|
||||
boost::ignore_unused(bytes_transferred);
|
||||
|
||||
if(ec == http::error::end_of_stream)
|
||||
if(ec)
|
||||
return fail(ec, "write");
|
||||
|
||||
if(close)
|
||||
{
|
||||
// This means we should close the connection, usually because
|
||||
// the response indicated the "Connection: close" semantic.
|
||||
return do_close();
|
||||
}
|
||||
|
||||
if(ec)
|
||||
return fail(ec, "write");
|
||||
|
||||
// We're done with the response so delete it
|
||||
res_ = nullptr;
|
||||
|
||||
|
||||
@@ -244,7 +244,8 @@ class session : public std::enable_shared_from_this<session>
|
||||
&session::on_write,
|
||||
self_.shared_from_this(),
|
||||
std::placeholders::_1,
|
||||
std::placeholders::_2)));
|
||||
std::placeholders::_2,
|
||||
! sp->keep_alive())));
|
||||
}
|
||||
};
|
||||
|
||||
@@ -309,20 +310,21 @@ public:
|
||||
void
|
||||
on_write(
|
||||
boost::system::error_code ec,
|
||||
std::size_t bytes_transferred)
|
||||
std::size_t bytes_transferred,
|
||||
bool close)
|
||||
{
|
||||
boost::ignore_unused(bytes_transferred);
|
||||
|
||||
if(ec == http::error::end_of_stream)
|
||||
if(ec)
|
||||
return fail(ec, "write");
|
||||
|
||||
if(close)
|
||||
{
|
||||
// This means we should close the connection, usually because
|
||||
// the response indicated the "Connection: close" semantic.
|
||||
return do_close();
|
||||
}
|
||||
|
||||
if(ec)
|
||||
return fail(ec, "write");
|
||||
|
||||
// We're done with the response so delete it
|
||||
res_ = nullptr;
|
||||
|
||||
|
||||
@@ -216,15 +216,18 @@ template<class Stream>
|
||||
struct send_lambda
|
||||
{
|
||||
Stream& stream_;
|
||||
bool& close_;
|
||||
boost::system::error_code& ec_;
|
||||
boost::asio::yield_context yield_;
|
||||
|
||||
explicit
|
||||
send_lambda(
|
||||
Stream& stream,
|
||||
bool& close,
|
||||
boost::system::error_code& ec,
|
||||
boost::asio::yield_context yield)
|
||||
: stream_(stream)
|
||||
, close_(close)
|
||||
, ec_(ec)
|
||||
, yield_(yield)
|
||||
{
|
||||
@@ -234,6 +237,9 @@ struct send_lambda
|
||||
void
|
||||
operator()(http::message<isRequest, Body, Fields>&& msg) const
|
||||
{
|
||||
// Determine if we should close the connection after
|
||||
close_ = ! msg.keep_alive();
|
||||
|
||||
// We need the serializer here because the serializer requires
|
||||
// a non-const file_body, and the message oriented version of
|
||||
// http::write only works with const messages.
|
||||
@@ -250,6 +256,7 @@ do_session(
|
||||
std::string const& doc_root,
|
||||
boost::asio::yield_context yield)
|
||||
{
|
||||
bool close = false;
|
||||
boost::system::error_code ec;
|
||||
|
||||
// Construct the stream around the socket
|
||||
@@ -264,7 +271,7 @@ do_session(
|
||||
boost::beast::flat_buffer buffer;
|
||||
|
||||
// This lambda is used to send messages
|
||||
send_lambda<ssl::stream<tcp::socket&>> lambda{stream, ec, yield};
|
||||
send_lambda<ssl::stream<tcp::socket&>> lambda{stream, close, ec, yield};
|
||||
|
||||
for(;;)
|
||||
{
|
||||
@@ -278,14 +285,14 @@ do_session(
|
||||
|
||||
// Send the response
|
||||
handle_request(doc_root, std::move(req), lambda);
|
||||
if(ec == http::error::end_of_stream)
|
||||
if(ec)
|
||||
return fail(ec, "write");
|
||||
if(close)
|
||||
{
|
||||
// This means we should close the connection, usually because
|
||||
// the response indicated the "Connection: close" semantic.
|
||||
break;
|
||||
}
|
||||
if(ec)
|
||||
return fail(ec, "write");
|
||||
}
|
||||
|
||||
// Perform the SSL shutdown
|
||||
|
||||
@@ -212,15 +212,18 @@ template<class Stream>
|
||||
struct send_lambda
|
||||
{
|
||||
Stream& stream_;
|
||||
bool& close_;
|
||||
boost::system::error_code& ec_;
|
||||
boost::asio::yield_context yield_;
|
||||
|
||||
explicit
|
||||
send_lambda(
|
||||
Stream& stream,
|
||||
bool& close,
|
||||
boost::system::error_code& ec,
|
||||
boost::asio::yield_context yield)
|
||||
: stream_(stream)
|
||||
, close_(close)
|
||||
, ec_(ec)
|
||||
, yield_(yield)
|
||||
{
|
||||
@@ -230,6 +233,9 @@ struct send_lambda
|
||||
void
|
||||
operator()(http::message<isRequest, Body, Fields>&& msg) const
|
||||
{
|
||||
// Determine if we should close the connection after
|
||||
close_ = ! msg.keep_alive();
|
||||
|
||||
// We need the serializer here because the serializer requires
|
||||
// a non-const file_body, and the message oriented version of
|
||||
// http::write only works with const messages.
|
||||
@@ -245,13 +251,14 @@ do_session(
|
||||
std::string const& doc_root,
|
||||
boost::asio::yield_context yield)
|
||||
{
|
||||
bool close = false;
|
||||
boost::system::error_code ec;
|
||||
|
||||
// This buffer is required to persist across reads
|
||||
boost::beast::flat_buffer buffer;
|
||||
|
||||
// This lambda is used to send messages
|
||||
send_lambda<tcp::socket> lambda{socket, ec, yield};
|
||||
send_lambda<tcp::socket> lambda{socket, close, ec, yield};
|
||||
|
||||
for(;;)
|
||||
{
|
||||
@@ -265,14 +272,14 @@ do_session(
|
||||
|
||||
// Send the response
|
||||
handle_request(doc_root, std::move(req), lambda);
|
||||
if(ec == http::error::end_of_stream)
|
||||
if(ec)
|
||||
return fail(ec, "write");
|
||||
if(close)
|
||||
{
|
||||
// This means we should close the connection, usually because
|
||||
// the response indicated the "Connection: close" semantic.
|
||||
break;
|
||||
}
|
||||
if(ec)
|
||||
return fail(ec, "write");
|
||||
}
|
||||
|
||||
// Send a TCP shutdown
|
||||
|
||||
@@ -209,8 +209,8 @@ private:
|
||||
std::make_tuple(alloc_));
|
||||
|
||||
string_response_->result(status);
|
||||
string_response_->keep_alive(false);
|
||||
string_response_->set(http::field::server, "Beast");
|
||||
string_response_->set(http::field::connection, "close");
|
||||
string_response_->set(http::field::content_type, "text/plain");
|
||||
string_response_->body() = error;
|
||||
string_response_->prepare_payload();
|
||||
@@ -265,8 +265,8 @@ private:
|
||||
std::make_tuple(alloc_));
|
||||
|
||||
file_response_->result(http::status::ok);
|
||||
file_response_->keep_alive(false);
|
||||
file_response_->set(http::field::server, "Beast");
|
||||
file_response_->set(http::field::connection, "close");
|
||||
file_response_->set(http::field::content_type, mime_type(target.to_string()));
|
||||
file_response_->body() = std::move(file);
|
||||
file_response_->prepare_payload();
|
||||
|
||||
@@ -259,7 +259,8 @@ class session
|
||||
&session::on_write,
|
||||
self_.derived().shared_from_this(),
|
||||
std::placeholders::_1,
|
||||
std::placeholders::_2)));
|
||||
std::placeholders::_2,
|
||||
! sp->keep_alive())));
|
||||
}
|
||||
};
|
||||
|
||||
@@ -322,20 +323,21 @@ public:
|
||||
void
|
||||
on_write(
|
||||
boost::system::error_code ec,
|
||||
std::size_t bytes_transferred)
|
||||
std::size_t bytes_transferred,
|
||||
bool close)
|
||||
{
|
||||
boost::ignore_unused(bytes_transferred);
|
||||
|
||||
if(ec == http::error::end_of_stream)
|
||||
if(ec)
|
||||
return fail(ec, "write");
|
||||
|
||||
if(close)
|
||||
{
|
||||
// This means we should close the connection, usually because
|
||||
// the response indicated the "Connection: close" semantic.
|
||||
return derived().do_eof();
|
||||
}
|
||||
|
||||
if(ec)
|
||||
return fail(ec, "write");
|
||||
|
||||
// We're done with the response so delete it
|
||||
res_ = nullptr;
|
||||
|
||||
|
||||
@@ -100,8 +100,8 @@ private:
|
||||
void
|
||||
process_request()
|
||||
{
|
||||
response_.version(11);
|
||||
response_.set(http::field::connection, "close");
|
||||
response_.version(request_.version());
|
||||
response_.keep_alive(false);
|
||||
|
||||
switch(request_.method())
|
||||
{
|
||||
|
||||
@@ -251,7 +251,8 @@ class session
|
||||
&session::loop,
|
||||
self_.shared_from_this(),
|
||||
std::placeholders::_1,
|
||||
std::placeholders::_2)));
|
||||
std::placeholders::_2,
|
||||
! sp->keep_alive())));
|
||||
}
|
||||
};
|
||||
|
||||
@@ -283,14 +284,15 @@ public:
|
||||
void
|
||||
run()
|
||||
{
|
||||
loop({}, 0);
|
||||
loop({}, 0, false);
|
||||
}
|
||||
|
||||
#include <boost/asio/yield.hpp>
|
||||
void
|
||||
loop(
|
||||
boost::system::error_code ec,
|
||||
std::size_t bytes_transferred)
|
||||
std::size_t bytes_transferred,
|
||||
bool close)
|
||||
{
|
||||
boost::ignore_unused(bytes_transferred);
|
||||
reenter(*this)
|
||||
@@ -302,7 +304,8 @@ public:
|
||||
&session::loop,
|
||||
shared_from_this(),
|
||||
std::placeholders::_1,
|
||||
0)));
|
||||
0,
|
||||
false)));
|
||||
if(ec)
|
||||
return fail(ec, "handshake");
|
||||
|
||||
@@ -314,7 +317,8 @@ public:
|
||||
&session::loop,
|
||||
shared_from_this(),
|
||||
std::placeholders::_1,
|
||||
std::placeholders::_2)));
|
||||
std::placeholders::_2,
|
||||
false)));
|
||||
if(ec == http::error::end_of_stream)
|
||||
{
|
||||
// The remote host closed the connection
|
||||
@@ -325,14 +329,14 @@ public:
|
||||
|
||||
// Send the response
|
||||
yield handle_request(doc_root_, std::move(req_), lambda_);
|
||||
if(ec == http::error::end_of_stream)
|
||||
if(ec)
|
||||
return fail(ec, "write");
|
||||
if(close)
|
||||
{
|
||||
// This means we should close the connection, usually because
|
||||
// the response indicated the "Connection: close" semantic.
|
||||
break;
|
||||
}
|
||||
if(ec)
|
||||
return fail(ec, "write");
|
||||
|
||||
// We're done with the response so delete it
|
||||
res_ = nullptr;
|
||||
@@ -344,7 +348,8 @@ public:
|
||||
&session::loop,
|
||||
shared_from_this(),
|
||||
std::placeholders::_1,
|
||||
0)));
|
||||
0,
|
||||
false)));
|
||||
if(ec)
|
||||
return fail(ec, "shutdown");
|
||||
|
||||
|
||||
@@ -248,7 +248,8 @@ class session
|
||||
&session::loop,
|
||||
self_.shared_from_this(),
|
||||
std::placeholders::_1,
|
||||
std::placeholders::_2)));
|
||||
std::placeholders::_2,
|
||||
! sp->keep_alive())));
|
||||
}
|
||||
};
|
||||
|
||||
@@ -277,14 +278,15 @@ public:
|
||||
void
|
||||
run()
|
||||
{
|
||||
loop({}, 0);
|
||||
loop({}, 0, false);
|
||||
}
|
||||
|
||||
#include <boost/asio/yield.hpp>
|
||||
void
|
||||
loop(
|
||||
boost::system::error_code ec,
|
||||
std::size_t bytes_transferred)
|
||||
std::size_t bytes_transferred,
|
||||
bool close)
|
||||
{
|
||||
boost::ignore_unused(bytes_transferred);
|
||||
reenter(*this)
|
||||
@@ -297,7 +299,8 @@ public:
|
||||
&session::loop,
|
||||
shared_from_this(),
|
||||
std::placeholders::_1,
|
||||
std::placeholders::_2)));
|
||||
std::placeholders::_2,
|
||||
false)));
|
||||
if(ec == http::error::end_of_stream)
|
||||
{
|
||||
// The remote host closed the connection
|
||||
@@ -308,14 +311,14 @@ public:
|
||||
|
||||
// Send the response
|
||||
yield handle_request(doc_root_, std::move(req_), lambda_);
|
||||
if(ec == http::error::end_of_stream)
|
||||
if(ec)
|
||||
return fail(ec, "write");
|
||||
if(close)
|
||||
{
|
||||
// This means we should close the connection, usually because
|
||||
// the response indicated the "Connection: close" semantic.
|
||||
break;
|
||||
}
|
||||
if(ec)
|
||||
return fail(ec, "write");
|
||||
|
||||
// We're done with the response so delete it
|
||||
res_ = nullptr;
|
||||
|
||||
@@ -213,13 +213,16 @@ template<class Stream>
|
||||
struct send_lambda
|
||||
{
|
||||
Stream& stream_;
|
||||
bool& close_;
|
||||
boost::system::error_code& ec_;
|
||||
|
||||
explicit
|
||||
send_lambda(
|
||||
Stream& stream,
|
||||
bool& close,
|
||||
boost::system::error_code& ec)
|
||||
: stream_(stream)
|
||||
, close_(close)
|
||||
, ec_(ec)
|
||||
{
|
||||
}
|
||||
@@ -228,6 +231,9 @@ struct send_lambda
|
||||
void
|
||||
operator()(http::message<isRequest, Body, Fields>&& msg) const
|
||||
{
|
||||
// Determine if we should close the connection after
|
||||
close_ = ! msg.keep_alive();
|
||||
|
||||
// We need the serializer here because the serializer requires
|
||||
// a non-const file_body, and the message oriented version of
|
||||
// http::write only works with const messages.
|
||||
@@ -243,6 +249,7 @@ do_session(
|
||||
ssl::context& ctx,
|
||||
std::string const& doc_root)
|
||||
{
|
||||
bool close = false;
|
||||
boost::system::error_code ec;
|
||||
|
||||
// Construct the stream around the socket
|
||||
@@ -257,7 +264,7 @@ do_session(
|
||||
boost::beast::flat_buffer buffer;
|
||||
|
||||
// This lambda is used to send messages
|
||||
send_lambda<ssl::stream<tcp::socket&>> lambda{stream, ec};
|
||||
send_lambda<ssl::stream<tcp::socket&>> lambda{stream, close, ec};
|
||||
|
||||
for(;;)
|
||||
{
|
||||
@@ -271,14 +278,14 @@ do_session(
|
||||
|
||||
// Send the response
|
||||
handle_request(doc_root, std::move(req), lambda);
|
||||
if(ec == http::error::end_of_stream)
|
||||
if(ec)
|
||||
return fail(ec, "write");
|
||||
if(close)
|
||||
{
|
||||
// This means we should close the connection, usually because
|
||||
// the response indicated the "Connection: close" semantic.
|
||||
break;
|
||||
}
|
||||
if(ec)
|
||||
return fail(ec, "write");
|
||||
}
|
||||
|
||||
// Perform the SSL shutdown
|
||||
|
||||
@@ -211,13 +211,16 @@ template<class Stream>
|
||||
struct send_lambda
|
||||
{
|
||||
Stream& stream_;
|
||||
bool& close_;
|
||||
boost::system::error_code& ec_;
|
||||
|
||||
explicit
|
||||
send_lambda(
|
||||
Stream& stream,
|
||||
bool& close,
|
||||
boost::system::error_code& ec)
|
||||
: stream_(stream)
|
||||
, close_(close)
|
||||
, ec_(ec)
|
||||
{
|
||||
}
|
||||
@@ -226,6 +229,9 @@ struct send_lambda
|
||||
void
|
||||
operator()(http::message<isRequest, Body, Fields>&& msg) const
|
||||
{
|
||||
// Determine if we should close the connection after
|
||||
close_ = ! msg.keep_alive();
|
||||
|
||||
// We need the serializer here because the serializer requires
|
||||
// a non-const file_body, and the message oriented version of
|
||||
// http::write only works with const messages.
|
||||
@@ -240,13 +246,14 @@ do_session(
|
||||
tcp::socket& socket,
|
||||
std::string const& doc_root)
|
||||
{
|
||||
bool close = false;
|
||||
boost::system::error_code ec;
|
||||
|
||||
// This buffer is required to persist across reads
|
||||
boost::beast::flat_buffer buffer;
|
||||
|
||||
// This lambda is used to send messages
|
||||
send_lambda<tcp::socket> lambda{socket, ec};
|
||||
send_lambda<tcp::socket> lambda{socket, close, ec};
|
||||
|
||||
for(;;)
|
||||
{
|
||||
@@ -260,14 +267,14 @@ do_session(
|
||||
|
||||
// Send the response
|
||||
handle_request(doc_root, std::move(req), lambda);
|
||||
if(ec == http::error::end_of_stream)
|
||||
if(ec)
|
||||
return fail(ec, "write");
|
||||
if(close)
|
||||
{
|
||||
// This means we should close the connection, usually because
|
||||
// the response indicated the "Connection: close" semantic.
|
||||
break;
|
||||
}
|
||||
if(ec)
|
||||
return fail(ec, "write");
|
||||
}
|
||||
|
||||
// Send a TCP shutdown
|
||||
|
||||
Reference in New Issue
Block a user