61 std::optional<boost::beast::http::request<boost::beast::http::string_body>> request_;
64 using MessageType = boost::beast::http::response<boost::beast::http::string_body>;
71 boost::asio::ip::tcp::socket socket,
73 boost::beast::flat_buffer buffer,
78 , stream_{std::move(socket)}
79 , sendingQueue_([
this](MessageType
const& message,
auto&& yield) {
80 boost::beast::get_lowest_layer(stream_).expires_after(timeout_);
81 boost::beast::http::async_write(stream_, message, yield);
87 boost::asio::ip::tcp::socket socket,
89 boost::beast::flat_buffer buffer,
90 boost::asio::ssl::context& sslCtx,
95 , stream_{std::move(socket), sslCtx}
96 , sendingQueue_([
this](MessageType
const& message,
auto&& yield) {
97 boost::beast::get_lowest_layer(stream_).expires_after(timeout_);
98 boost::beast::http::async_write(stream_, message, yield);
103 HttpConnection(HttpConnection&& other) =
delete;
105 operator=(HttpConnection&& other) =
delete;
106 HttpConnection(HttpConnection
const& other) =
delete;
108 operator=(HttpConnection
const& other) =
delete;
110 std::expected<void, Error>
111 sslHandshake(boost::asio::yield_context yield)
114 boost::system::error_code error;
115 boost::beast::get_lowest_layer(stream_).expires_after(timeout_);
116 auto const bytesUsed = stream_.async_handshake(
117 boost::asio::ssl::stream_base::server, buffer_.cdata(), yield[error]
120 return std::unexpected{error};
122 buffer_.consume(bytesUsed);
133 std::expected<void, Error>
135 boost::beast::http::response<boost::beast::http::string_body> response,
136 boost::asio::yield_context yield
139 return sendingQueue_.send(std::move(response), yield);
143 setTimeout(std::chrono::steady_clock::duration newTimeout)
override
145 timeout_ = newTimeout;
148 std::expected<void, Error>
151 auto httpResponse = std::move(response).intoHttpResponse();
152 return sendRaw(std::move(httpResponse), yield);
155 std::expected<Request, Error>
156 receive(boost::asio::yield_context yield)
override
158 if (request_.has_value()) {
159 Request result{std::move(request_).value()};
163 auto expectedRequest = fetch(yield);
164 if (expectedRequest.has_value())
165 return Request{std::move(expectedRequest).value()};
167 return std::unexpected{std::move(expectedRequest).error()};
171 close(boost::asio::yield_context yield)
override
180 [[maybe_unused]] boost::system::error_code error;
182 boost::beast::get_lowest_layer(stream_).expires_after(timeout_);
183 stream_.async_shutdown(yield[error]);
185 boost::beast::get_lowest_layer(stream_).socket().shutdown(
186 boost::asio::ip::tcp::socket::shutdown_type::shutdown_both, error
190 std::expected<bool, Error>
191 isUpgradeRequested(boost::asio::yield_context yield)
override
193 auto expectedRequest = fetch(yield);
194 if (not expectedRequest.has_value())
195 return std::unexpected{std::move(expectedRequest).error()};
197 request_ = std::move(expectedRequest).value();
199 return boost::beast::websocket::is_upgrade(request_.value());
202 std::expected<ConnectionPtr, Error>
205 boost::asio::yield_context yield
208 ASSERT(request_.has_value(),
"Request must be present to upgrade the connection");
210 return makeWsConnection(
214 std::move(request_).value(),
221 std::expected<boost::beast::http::request<boost::beast::http::string_body>, Error>
222 fetch(boost::asio::yield_context yield)
224 boost::beast::http::request<boost::beast::http::string_body> request{};
225 boost::system::error_code error;
226 boost::beast::get_lowest_layer(stream_).expires_after(timeout_);
227 boost::beast::http::async_read(stream_, buffer_, request, yield[error]);
229 return std::unexpected{error};