mirror of
https://github.com/boostorg/beast.git
synced 2025-07-31 13:27:33 +02:00
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:
13
CHANGELOG.md
13
CHANGELOG.md
@@ -1,3 +1,16 @@
|
|||||||
|
Version 124:
|
||||||
|
|
||||||
|
API Changes:
|
||||||
|
|
||||||
|
* http write returns success on connection close
|
||||||
|
|
||||||
|
Actions Required:
|
||||||
|
|
||||||
|
* Add code to servers to close the connection after successfully
|
||||||
|
writing a message where `message::keep_alive()` would return `false`.
|
||||||
|
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
Version 123:
|
Version 123:
|
||||||
|
|
||||||
* Use unit-test subtree
|
* Use unit-test subtree
|
||||||
|
@@ -248,7 +248,8 @@ class session : public std::enable_shared_from_this<session>
|
|||||||
&session::on_write,
|
&session::on_write,
|
||||||
self_.shared_from_this(),
|
self_.shared_from_this(),
|
||||||
std::placeholders::_1,
|
std::placeholders::_1,
|
||||||
std::placeholders::_2)));
|
std::placeholders::_2,
|
||||||
|
! sp->keep_alive())));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -331,20 +332,21 @@ public:
|
|||||||
void
|
void
|
||||||
on_write(
|
on_write(
|
||||||
boost::system::error_code ec,
|
boost::system::error_code ec,
|
||||||
std::size_t bytes_transferred)
|
std::size_t bytes_transferred,
|
||||||
|
bool close)
|
||||||
{
|
{
|
||||||
boost::ignore_unused(bytes_transferred);
|
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
|
// This means we should close the connection, usually because
|
||||||
// the response indicated the "Connection: close" semantic.
|
// the response indicated the "Connection: close" semantic.
|
||||||
return do_close();
|
return do_close();
|
||||||
}
|
}
|
||||||
|
|
||||||
if(ec)
|
|
||||||
return fail(ec, "write");
|
|
||||||
|
|
||||||
// We're done with the response so delete it
|
// We're done with the response so delete it
|
||||||
res_ = nullptr;
|
res_ = nullptr;
|
||||||
|
|
||||||
|
@@ -244,7 +244,8 @@ class session : public std::enable_shared_from_this<session>
|
|||||||
&session::on_write,
|
&session::on_write,
|
||||||
self_.shared_from_this(),
|
self_.shared_from_this(),
|
||||||
std::placeholders::_1,
|
std::placeholders::_1,
|
||||||
std::placeholders::_2)));
|
std::placeholders::_2,
|
||||||
|
! sp->keep_alive())));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -309,20 +310,21 @@ public:
|
|||||||
void
|
void
|
||||||
on_write(
|
on_write(
|
||||||
boost::system::error_code ec,
|
boost::system::error_code ec,
|
||||||
std::size_t bytes_transferred)
|
std::size_t bytes_transferred,
|
||||||
|
bool close)
|
||||||
{
|
{
|
||||||
boost::ignore_unused(bytes_transferred);
|
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
|
// This means we should close the connection, usually because
|
||||||
// the response indicated the "Connection: close" semantic.
|
// the response indicated the "Connection: close" semantic.
|
||||||
return do_close();
|
return do_close();
|
||||||
}
|
}
|
||||||
|
|
||||||
if(ec)
|
|
||||||
return fail(ec, "write");
|
|
||||||
|
|
||||||
// We're done with the response so delete it
|
// We're done with the response so delete it
|
||||||
res_ = nullptr;
|
res_ = nullptr;
|
||||||
|
|
||||||
|
@@ -216,15 +216,18 @@ template<class Stream>
|
|||||||
struct send_lambda
|
struct send_lambda
|
||||||
{
|
{
|
||||||
Stream& stream_;
|
Stream& stream_;
|
||||||
|
bool& close_;
|
||||||
boost::system::error_code& ec_;
|
boost::system::error_code& ec_;
|
||||||
boost::asio::yield_context yield_;
|
boost::asio::yield_context yield_;
|
||||||
|
|
||||||
explicit
|
explicit
|
||||||
send_lambda(
|
send_lambda(
|
||||||
Stream& stream,
|
Stream& stream,
|
||||||
|
bool& close,
|
||||||
boost::system::error_code& ec,
|
boost::system::error_code& ec,
|
||||||
boost::asio::yield_context yield)
|
boost::asio::yield_context yield)
|
||||||
: stream_(stream)
|
: stream_(stream)
|
||||||
|
, close_(close)
|
||||||
, ec_(ec)
|
, ec_(ec)
|
||||||
, yield_(yield)
|
, yield_(yield)
|
||||||
{
|
{
|
||||||
@@ -234,6 +237,9 @@ struct send_lambda
|
|||||||
void
|
void
|
||||||
operator()(http::message<isRequest, Body, Fields>&& msg) const
|
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
|
// We need the serializer here because the serializer requires
|
||||||
// a non-const file_body, and the message oriented version of
|
// a non-const file_body, and the message oriented version of
|
||||||
// http::write only works with const messages.
|
// http::write only works with const messages.
|
||||||
@@ -250,6 +256,7 @@ do_session(
|
|||||||
std::string const& doc_root,
|
std::string const& doc_root,
|
||||||
boost::asio::yield_context yield)
|
boost::asio::yield_context yield)
|
||||||
{
|
{
|
||||||
|
bool close = false;
|
||||||
boost::system::error_code ec;
|
boost::system::error_code ec;
|
||||||
|
|
||||||
// Construct the stream around the socket
|
// Construct the stream around the socket
|
||||||
@@ -264,7 +271,7 @@ do_session(
|
|||||||
boost::beast::flat_buffer buffer;
|
boost::beast::flat_buffer buffer;
|
||||||
|
|
||||||
// This lambda is used to send messages
|
// 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(;;)
|
for(;;)
|
||||||
{
|
{
|
||||||
@@ -278,14 +285,14 @@ do_session(
|
|||||||
|
|
||||||
// Send the response
|
// Send the response
|
||||||
handle_request(doc_root, std::move(req), lambda);
|
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
|
// This means we should close the connection, usually because
|
||||||
// the response indicated the "Connection: close" semantic.
|
// the response indicated the "Connection: close" semantic.
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if(ec)
|
|
||||||
return fail(ec, "write");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Perform the SSL shutdown
|
// Perform the SSL shutdown
|
||||||
|
@@ -212,15 +212,18 @@ template<class Stream>
|
|||||||
struct send_lambda
|
struct send_lambda
|
||||||
{
|
{
|
||||||
Stream& stream_;
|
Stream& stream_;
|
||||||
|
bool& close_;
|
||||||
boost::system::error_code& ec_;
|
boost::system::error_code& ec_;
|
||||||
boost::asio::yield_context yield_;
|
boost::asio::yield_context yield_;
|
||||||
|
|
||||||
explicit
|
explicit
|
||||||
send_lambda(
|
send_lambda(
|
||||||
Stream& stream,
|
Stream& stream,
|
||||||
|
bool& close,
|
||||||
boost::system::error_code& ec,
|
boost::system::error_code& ec,
|
||||||
boost::asio::yield_context yield)
|
boost::asio::yield_context yield)
|
||||||
: stream_(stream)
|
: stream_(stream)
|
||||||
|
, close_(close)
|
||||||
, ec_(ec)
|
, ec_(ec)
|
||||||
, yield_(yield)
|
, yield_(yield)
|
||||||
{
|
{
|
||||||
@@ -230,6 +233,9 @@ struct send_lambda
|
|||||||
void
|
void
|
||||||
operator()(http::message<isRequest, Body, Fields>&& msg) const
|
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
|
// We need the serializer here because the serializer requires
|
||||||
// a non-const file_body, and the message oriented version of
|
// a non-const file_body, and the message oriented version of
|
||||||
// http::write only works with const messages.
|
// http::write only works with const messages.
|
||||||
@@ -245,13 +251,14 @@ do_session(
|
|||||||
std::string const& doc_root,
|
std::string const& doc_root,
|
||||||
boost::asio::yield_context yield)
|
boost::asio::yield_context yield)
|
||||||
{
|
{
|
||||||
|
bool close = false;
|
||||||
boost::system::error_code ec;
|
boost::system::error_code ec;
|
||||||
|
|
||||||
// This buffer is required to persist across reads
|
// This buffer is required to persist across reads
|
||||||
boost::beast::flat_buffer buffer;
|
boost::beast::flat_buffer buffer;
|
||||||
|
|
||||||
// This lambda is used to send messages
|
// 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(;;)
|
for(;;)
|
||||||
{
|
{
|
||||||
@@ -265,14 +272,14 @@ do_session(
|
|||||||
|
|
||||||
// Send the response
|
// Send the response
|
||||||
handle_request(doc_root, std::move(req), lambda);
|
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
|
// This means we should close the connection, usually because
|
||||||
// the response indicated the "Connection: close" semantic.
|
// the response indicated the "Connection: close" semantic.
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if(ec)
|
|
||||||
return fail(ec, "write");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Send a TCP shutdown
|
// Send a TCP shutdown
|
||||||
|
@@ -209,8 +209,8 @@ private:
|
|||||||
std::make_tuple(alloc_));
|
std::make_tuple(alloc_));
|
||||||
|
|
||||||
string_response_->result(status);
|
string_response_->result(status);
|
||||||
|
string_response_->keep_alive(false);
|
||||||
string_response_->set(http::field::server, "Beast");
|
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_->set(http::field::content_type, "text/plain");
|
||||||
string_response_->body() = error;
|
string_response_->body() = error;
|
||||||
string_response_->prepare_payload();
|
string_response_->prepare_payload();
|
||||||
@@ -265,8 +265,8 @@ private:
|
|||||||
std::make_tuple(alloc_));
|
std::make_tuple(alloc_));
|
||||||
|
|
||||||
file_response_->result(http::status::ok);
|
file_response_->result(http::status::ok);
|
||||||
|
file_response_->keep_alive(false);
|
||||||
file_response_->set(http::field::server, "Beast");
|
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_->set(http::field::content_type, mime_type(target.to_string()));
|
||||||
file_response_->body() = std::move(file);
|
file_response_->body() = std::move(file);
|
||||||
file_response_->prepare_payload();
|
file_response_->prepare_payload();
|
||||||
|
@@ -259,7 +259,8 @@ class session
|
|||||||
&session::on_write,
|
&session::on_write,
|
||||||
self_.derived().shared_from_this(),
|
self_.derived().shared_from_this(),
|
||||||
std::placeholders::_1,
|
std::placeholders::_1,
|
||||||
std::placeholders::_2)));
|
std::placeholders::_2,
|
||||||
|
! sp->keep_alive())));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -322,20 +323,21 @@ public:
|
|||||||
void
|
void
|
||||||
on_write(
|
on_write(
|
||||||
boost::system::error_code ec,
|
boost::system::error_code ec,
|
||||||
std::size_t bytes_transferred)
|
std::size_t bytes_transferred,
|
||||||
|
bool close)
|
||||||
{
|
{
|
||||||
boost::ignore_unused(bytes_transferred);
|
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
|
// This means we should close the connection, usually because
|
||||||
// the response indicated the "Connection: close" semantic.
|
// the response indicated the "Connection: close" semantic.
|
||||||
return derived().do_eof();
|
return derived().do_eof();
|
||||||
}
|
}
|
||||||
|
|
||||||
if(ec)
|
|
||||||
return fail(ec, "write");
|
|
||||||
|
|
||||||
// We're done with the response so delete it
|
// We're done with the response so delete it
|
||||||
res_ = nullptr;
|
res_ = nullptr;
|
||||||
|
|
||||||
|
@@ -100,8 +100,8 @@ private:
|
|||||||
void
|
void
|
||||||
process_request()
|
process_request()
|
||||||
{
|
{
|
||||||
response_.version(11);
|
response_.version(request_.version());
|
||||||
response_.set(http::field::connection, "close");
|
response_.keep_alive(false);
|
||||||
|
|
||||||
switch(request_.method())
|
switch(request_.method())
|
||||||
{
|
{
|
||||||
|
@@ -251,7 +251,8 @@ class session
|
|||||||
&session::loop,
|
&session::loop,
|
||||||
self_.shared_from_this(),
|
self_.shared_from_this(),
|
||||||
std::placeholders::_1,
|
std::placeholders::_1,
|
||||||
std::placeholders::_2)));
|
std::placeholders::_2,
|
||||||
|
! sp->keep_alive())));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -283,14 +284,15 @@ public:
|
|||||||
void
|
void
|
||||||
run()
|
run()
|
||||||
{
|
{
|
||||||
loop({}, 0);
|
loop({}, 0, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
#include <boost/asio/yield.hpp>
|
#include <boost/asio/yield.hpp>
|
||||||
void
|
void
|
||||||
loop(
|
loop(
|
||||||
boost::system::error_code ec,
|
boost::system::error_code ec,
|
||||||
std::size_t bytes_transferred)
|
std::size_t bytes_transferred,
|
||||||
|
bool close)
|
||||||
{
|
{
|
||||||
boost::ignore_unused(bytes_transferred);
|
boost::ignore_unused(bytes_transferred);
|
||||||
reenter(*this)
|
reenter(*this)
|
||||||
@@ -302,7 +304,8 @@ public:
|
|||||||
&session::loop,
|
&session::loop,
|
||||||
shared_from_this(),
|
shared_from_this(),
|
||||||
std::placeholders::_1,
|
std::placeholders::_1,
|
||||||
0)));
|
0,
|
||||||
|
false)));
|
||||||
if(ec)
|
if(ec)
|
||||||
return fail(ec, "handshake");
|
return fail(ec, "handshake");
|
||||||
|
|
||||||
@@ -314,7 +317,8 @@ public:
|
|||||||
&session::loop,
|
&session::loop,
|
||||||
shared_from_this(),
|
shared_from_this(),
|
||||||
std::placeholders::_1,
|
std::placeholders::_1,
|
||||||
std::placeholders::_2)));
|
std::placeholders::_2,
|
||||||
|
false)));
|
||||||
if(ec == http::error::end_of_stream)
|
if(ec == http::error::end_of_stream)
|
||||||
{
|
{
|
||||||
// The remote host closed the connection
|
// The remote host closed the connection
|
||||||
@@ -325,14 +329,14 @@ public:
|
|||||||
|
|
||||||
// Send the response
|
// Send the response
|
||||||
yield handle_request(doc_root_, std::move(req_), lambda_);
|
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
|
// This means we should close the connection, usually because
|
||||||
// the response indicated the "Connection: close" semantic.
|
// the response indicated the "Connection: close" semantic.
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if(ec)
|
|
||||||
return fail(ec, "write");
|
|
||||||
|
|
||||||
// We're done with the response so delete it
|
// We're done with the response so delete it
|
||||||
res_ = nullptr;
|
res_ = nullptr;
|
||||||
@@ -344,7 +348,8 @@ public:
|
|||||||
&session::loop,
|
&session::loop,
|
||||||
shared_from_this(),
|
shared_from_this(),
|
||||||
std::placeholders::_1,
|
std::placeholders::_1,
|
||||||
0)));
|
0,
|
||||||
|
false)));
|
||||||
if(ec)
|
if(ec)
|
||||||
return fail(ec, "shutdown");
|
return fail(ec, "shutdown");
|
||||||
|
|
||||||
|
@@ -248,7 +248,8 @@ class session
|
|||||||
&session::loop,
|
&session::loop,
|
||||||
self_.shared_from_this(),
|
self_.shared_from_this(),
|
||||||
std::placeholders::_1,
|
std::placeholders::_1,
|
||||||
std::placeholders::_2)));
|
std::placeholders::_2,
|
||||||
|
! sp->keep_alive())));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -277,14 +278,15 @@ public:
|
|||||||
void
|
void
|
||||||
run()
|
run()
|
||||||
{
|
{
|
||||||
loop({}, 0);
|
loop({}, 0, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
#include <boost/asio/yield.hpp>
|
#include <boost/asio/yield.hpp>
|
||||||
void
|
void
|
||||||
loop(
|
loop(
|
||||||
boost::system::error_code ec,
|
boost::system::error_code ec,
|
||||||
std::size_t bytes_transferred)
|
std::size_t bytes_transferred,
|
||||||
|
bool close)
|
||||||
{
|
{
|
||||||
boost::ignore_unused(bytes_transferred);
|
boost::ignore_unused(bytes_transferred);
|
||||||
reenter(*this)
|
reenter(*this)
|
||||||
@@ -297,7 +299,8 @@ public:
|
|||||||
&session::loop,
|
&session::loop,
|
||||||
shared_from_this(),
|
shared_from_this(),
|
||||||
std::placeholders::_1,
|
std::placeholders::_1,
|
||||||
std::placeholders::_2)));
|
std::placeholders::_2,
|
||||||
|
false)));
|
||||||
if(ec == http::error::end_of_stream)
|
if(ec == http::error::end_of_stream)
|
||||||
{
|
{
|
||||||
// The remote host closed the connection
|
// The remote host closed the connection
|
||||||
@@ -308,14 +311,14 @@ public:
|
|||||||
|
|
||||||
// Send the response
|
// Send the response
|
||||||
yield handle_request(doc_root_, std::move(req_), lambda_);
|
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
|
// This means we should close the connection, usually because
|
||||||
// the response indicated the "Connection: close" semantic.
|
// the response indicated the "Connection: close" semantic.
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if(ec)
|
|
||||||
return fail(ec, "write");
|
|
||||||
|
|
||||||
// We're done with the response so delete it
|
// We're done with the response so delete it
|
||||||
res_ = nullptr;
|
res_ = nullptr;
|
||||||
|
@@ -213,13 +213,16 @@ template<class Stream>
|
|||||||
struct send_lambda
|
struct send_lambda
|
||||||
{
|
{
|
||||||
Stream& stream_;
|
Stream& stream_;
|
||||||
|
bool& close_;
|
||||||
boost::system::error_code& ec_;
|
boost::system::error_code& ec_;
|
||||||
|
|
||||||
explicit
|
explicit
|
||||||
send_lambda(
|
send_lambda(
|
||||||
Stream& stream,
|
Stream& stream,
|
||||||
|
bool& close,
|
||||||
boost::system::error_code& ec)
|
boost::system::error_code& ec)
|
||||||
: stream_(stream)
|
: stream_(stream)
|
||||||
|
, close_(close)
|
||||||
, ec_(ec)
|
, ec_(ec)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@@ -228,6 +231,9 @@ struct send_lambda
|
|||||||
void
|
void
|
||||||
operator()(http::message<isRequest, Body, Fields>&& msg) const
|
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
|
// We need the serializer here because the serializer requires
|
||||||
// a non-const file_body, and the message oriented version of
|
// a non-const file_body, and the message oriented version of
|
||||||
// http::write only works with const messages.
|
// http::write only works with const messages.
|
||||||
@@ -243,6 +249,7 @@ do_session(
|
|||||||
ssl::context& ctx,
|
ssl::context& ctx,
|
||||||
std::string const& doc_root)
|
std::string const& doc_root)
|
||||||
{
|
{
|
||||||
|
bool close = false;
|
||||||
boost::system::error_code ec;
|
boost::system::error_code ec;
|
||||||
|
|
||||||
// Construct the stream around the socket
|
// Construct the stream around the socket
|
||||||
@@ -257,7 +264,7 @@ do_session(
|
|||||||
boost::beast::flat_buffer buffer;
|
boost::beast::flat_buffer buffer;
|
||||||
|
|
||||||
// This lambda is used to send messages
|
// 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(;;)
|
for(;;)
|
||||||
{
|
{
|
||||||
@@ -271,14 +278,14 @@ do_session(
|
|||||||
|
|
||||||
// Send the response
|
// Send the response
|
||||||
handle_request(doc_root, std::move(req), lambda);
|
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
|
// This means we should close the connection, usually because
|
||||||
// the response indicated the "Connection: close" semantic.
|
// the response indicated the "Connection: close" semantic.
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if(ec)
|
|
||||||
return fail(ec, "write");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Perform the SSL shutdown
|
// Perform the SSL shutdown
|
||||||
|
@@ -211,13 +211,16 @@ template<class Stream>
|
|||||||
struct send_lambda
|
struct send_lambda
|
||||||
{
|
{
|
||||||
Stream& stream_;
|
Stream& stream_;
|
||||||
|
bool& close_;
|
||||||
boost::system::error_code& ec_;
|
boost::system::error_code& ec_;
|
||||||
|
|
||||||
explicit
|
explicit
|
||||||
send_lambda(
|
send_lambda(
|
||||||
Stream& stream,
|
Stream& stream,
|
||||||
|
bool& close,
|
||||||
boost::system::error_code& ec)
|
boost::system::error_code& ec)
|
||||||
: stream_(stream)
|
: stream_(stream)
|
||||||
|
, close_(close)
|
||||||
, ec_(ec)
|
, ec_(ec)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@@ -226,6 +229,9 @@ struct send_lambda
|
|||||||
void
|
void
|
||||||
operator()(http::message<isRequest, Body, Fields>&& msg) const
|
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
|
// We need the serializer here because the serializer requires
|
||||||
// a non-const file_body, and the message oriented version of
|
// a non-const file_body, and the message oriented version of
|
||||||
// http::write only works with const messages.
|
// http::write only works with const messages.
|
||||||
@@ -240,13 +246,14 @@ do_session(
|
|||||||
tcp::socket& socket,
|
tcp::socket& socket,
|
||||||
std::string const& doc_root)
|
std::string const& doc_root)
|
||||||
{
|
{
|
||||||
|
bool close = false;
|
||||||
boost::system::error_code ec;
|
boost::system::error_code ec;
|
||||||
|
|
||||||
// This buffer is required to persist across reads
|
// This buffer is required to persist across reads
|
||||||
boost::beast::flat_buffer buffer;
|
boost::beast::flat_buffer buffer;
|
||||||
|
|
||||||
// This lambda is used to send messages
|
// This lambda is used to send messages
|
||||||
send_lambda<tcp::socket> lambda{socket, ec};
|
send_lambda<tcp::socket> lambda{socket, close, ec};
|
||||||
|
|
||||||
for(;;)
|
for(;;)
|
||||||
{
|
{
|
||||||
@@ -260,14 +267,14 @@ do_session(
|
|||||||
|
|
||||||
// Send the response
|
// Send the response
|
||||||
handle_request(doc_root, std::move(req), lambda);
|
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
|
// This means we should close the connection, usually because
|
||||||
// the response indicated the "Connection: close" semantic.
|
// the response indicated the "Connection: close" semantic.
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if(ec)
|
|
||||||
return fail(ec, "write");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Send a TCP shutdown
|
// Send a TCP shutdown
|
||||||
|
@@ -162,12 +162,7 @@ operator()(
|
|||||||
error_code ec, std::size_t bytes_transferred)
|
error_code ec, std::size_t bytes_transferred)
|
||||||
{
|
{
|
||||||
if(! ec)
|
if(! ec)
|
||||||
{
|
|
||||||
sr_.consume(bytes_transferred);
|
sr_.consume(bytes_transferred);
|
||||||
if(sr_.is_done())
|
|
||||||
if(! sr_.keep_alive())
|
|
||||||
ec = error::end_of_stream;
|
|
||||||
}
|
|
||||||
h_(ec, bytes_transferred);
|
h_(ec, bytes_transferred);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -478,14 +473,8 @@ write_some(
|
|||||||
return f.bytes_transferred;
|
return f.bytes_transferred;
|
||||||
if(f.invoked)
|
if(f.invoked)
|
||||||
sr.consume(f.bytes_transferred);
|
sr.consume(f.bytes_transferred);
|
||||||
if(sr.is_done())
|
|
||||||
if(! sr.keep_alive())
|
|
||||||
ec = error::end_of_stream;
|
|
||||||
return f.bytes_transferred;
|
return f.bytes_transferred;
|
||||||
}
|
}
|
||||||
if(! sr.keep_alive())
|
|
||||||
ec = error::end_of_stream;
|
|
||||||
else
|
|
||||||
ec.assign(0, ec.category());
|
ec.assign(0, ec.category());
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -909,8 +898,6 @@ operator<<(std::ostream& os,
|
|||||||
sr.next(ec, f);
|
sr.next(ec, f);
|
||||||
if(os.fail())
|
if(os.fail())
|
||||||
break;
|
break;
|
||||||
if(ec == error::end_of_stream)
|
|
||||||
ec.assign(0, ec.category());
|
|
||||||
if(ec)
|
if(ec)
|
||||||
{
|
{
|
||||||
os.setstate(std::ios::failbit);
|
os.setstate(std::ios::failbit);
|
||||||
|
@@ -440,9 +440,7 @@ async_write(
|
|||||||
|
|
||||||
This operation is implemented in terms of one or more calls to the stream's
|
This operation is implemented in terms of one or more calls to the stream's
|
||||||
`write_some` function. The algorithm will use a temporary @ref serializer
|
`write_some` function. The algorithm will use a temporary @ref serializer
|
||||||
with an empty chunk decorator to produce buffers. If the semantics of the
|
with an empty chunk decorator to produce buffers.
|
||||||
message indicate that the connection should be closed after the message is
|
|
||||||
sent, the error delivered by this function will be @ref error::end_of_stream
|
|
||||||
|
|
||||||
@param stream The stream to which the data is to be written.
|
@param stream The stream to which the data is to be written.
|
||||||
The type must support the @b SyncWriteStream concept.
|
The type must support the @b SyncWriteStream concept.
|
||||||
@@ -474,9 +472,7 @@ write(
|
|||||||
|
|
||||||
This operation is implemented in terms of one or more calls to the stream's
|
This operation is implemented in terms of one or more calls to the stream's
|
||||||
`write_some` function. The algorithm will use a temporary @ref serializer
|
`write_some` function. The algorithm will use a temporary @ref serializer
|
||||||
with an empty chunk decorator to produce buffers. If the semantics of the
|
with an empty chunk decorator to produce buffers.
|
||||||
message indicate that the connection should be closed after the message is
|
|
||||||
sent, the error delivered by this function will be @ref error::end_of_stream
|
|
||||||
|
|
||||||
@param stream The stream to which the data is to be written.
|
@param stream The stream to which the data is to be written.
|
||||||
The type must support the @b SyncWriteStream concept.
|
The type must support the @b SyncWriteStream concept.
|
||||||
@@ -512,10 +508,7 @@ write(
|
|||||||
`async_write_some` function, and is known as a <em>composed operation</em>.
|
`async_write_some` function, and is known as a <em>composed operation</em>.
|
||||||
The program must ensure that the stream performs no other write operations
|
The program must ensure that the stream performs no other write operations
|
||||||
until this operation completes. The algorithm will use a temporary
|
until this operation completes. The algorithm will use a temporary
|
||||||
@ref serializer with an empty chunk decorator to produce buffers. If
|
@ref serializer with an empty chunk decorator to produce buffers.
|
||||||
the semantics of the message indicate that the connection should be
|
|
||||||
closed after the message is sent, the error delivered by this function
|
|
||||||
will be @ref error::end_of_stream
|
|
||||||
|
|
||||||
@param stream The stream to which the data is to be written.
|
@param stream The stream to which the data is to be written.
|
||||||
The type must support the @b AsyncWriteStream concept.
|
The type must support the @b AsyncWriteStream concept.
|
||||||
|
@@ -328,7 +328,8 @@ public:
|
|||||||
test::stream ts{ios_}, tr{ios_};
|
test::stream ts{ios_}, tr{ios_};
|
||||||
ts.connect(tr);
|
ts.connect(tr);
|
||||||
async_write(ts, m, do_yield[ec]);
|
async_write(ts, m, do_yield[ec]);
|
||||||
if(BEAST_EXPECTS(ec == error::end_of_stream, ec.message()))
|
BEAST_EXPECT(! m.keep_alive());
|
||||||
|
if(BEAST_EXPECTS(! ec, ec.message()))
|
||||||
BEAST_EXPECT(tr.str() ==
|
BEAST_EXPECT(tr.str() ==
|
||||||
"HTTP/1.0 200 OK\r\n"
|
"HTTP/1.0 200 OK\r\n"
|
||||||
"Server: test\r\n"
|
"Server: test\r\n"
|
||||||
@@ -406,8 +407,9 @@ public:
|
|||||||
m.body() = "*****";
|
m.body() = "*****";
|
||||||
error_code ec = test::error::fail_error;
|
error_code ec = test::error::fail_error;
|
||||||
write(ts, m, ec);
|
write(ts, m, ec);
|
||||||
if(ec == error::end_of_stream)
|
if(! ec)
|
||||||
{
|
{
|
||||||
|
BEAST_EXPECT(! m.keep_alive());
|
||||||
BEAST_EXPECT(tr.str() ==
|
BEAST_EXPECT(tr.str() ==
|
||||||
"GET / HTTP/1.0\r\n"
|
"GET / HTTP/1.0\r\n"
|
||||||
"User-Agent: test\r\n"
|
"User-Agent: test\r\n"
|
||||||
@@ -436,8 +438,9 @@ public:
|
|||||||
m.body() = "*****";
|
m.body() = "*****";
|
||||||
error_code ec = test::error::fail_error;
|
error_code ec = test::error::fail_error;
|
||||||
async_write(ts, m, do_yield[ec]);
|
async_write(ts, m, do_yield[ec]);
|
||||||
if(ec == error::end_of_stream)
|
if(! ec)
|
||||||
{
|
{
|
||||||
|
BEAST_EXPECT(! m.keep_alive());
|
||||||
BEAST_EXPECT(tr.str() ==
|
BEAST_EXPECT(tr.str() ==
|
||||||
"GET / HTTP/1.0\r\n"
|
"GET / HTTP/1.0\r\n"
|
||||||
"User-Agent: test\r\n"
|
"User-Agent: test\r\n"
|
||||||
@@ -543,7 +546,8 @@ public:
|
|||||||
ts.connect(tr);
|
ts.connect(tr);
|
||||||
error_code ec;
|
error_code ec;
|
||||||
write(ts, m, ec);
|
write(ts, m, ec);
|
||||||
BEAST_EXPECT(ec == error::end_of_stream);
|
BEAST_EXPECT(! m.keep_alive());
|
||||||
|
BEAST_EXPECTS(! ec, ec.message());
|
||||||
BEAST_EXPECT(tr.str() ==
|
BEAST_EXPECT(tr.str() ==
|
||||||
"GET / HTTP/1.0\r\n"
|
"GET / HTTP/1.0\r\n"
|
||||||
"User-Agent: test\r\n"
|
"User-Agent: test\r\n"
|
||||||
|
@@ -484,7 +484,7 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
// wrong version
|
// wrong version
|
||||||
check(http::error::end_of_stream,
|
check(error::handshake_failed,
|
||||||
"GET / HTTP/1.0\r\n"
|
"GET / HTTP/1.0\r\n"
|
||||||
"Host: localhost:80\r\n"
|
"Host: localhost:80\r\n"
|
||||||
"Upgrade: WebSocket\r\n"
|
"Upgrade: WebSocket\r\n"
|
||||||
|
Reference in New Issue
Block a user