80 std::optional<boost::beast::http::request<boost::beast::http::string_body>> request_;
83 using MessageType = boost::beast::http::response<boost::beast::http::string_body>;
90 boost::asio::ip::tcp::socket socket,
92 boost::beast::flat_buffer buffer,
97 , stream_{std::move(socket)}
98 , sendingQueue_([
this](MessageType
const& message,
auto&& yield) {
99 boost::beast::get_lowest_layer(stream_).expires_after(timeout_);
100 boost::beast::http::async_write(stream_, message, yield);
106 boost::asio::ip::tcp::socket socket,
108 boost::beast::flat_buffer buffer,
109 boost::asio::ssl::context& sslCtx,
114 , stream_{std::move(socket), sslCtx}
115 , sendingQueue_([
this](MessageType
const& message,
auto&& yield) {
116 boost::beast::get_lowest_layer(stream_).expires_after(timeout_);
117 boost::beast::http::async_write(stream_, message, yield);
122 HttpConnection(HttpConnection&& other) =
delete;
124 operator=(HttpConnection&& other) =
delete;
125 HttpConnection(HttpConnection
const& other) =
delete;
127 operator=(HttpConnection
const& other) =
delete;
129 std::expected<void, Error>
130 sslHandshake(boost::asio::yield_context yield)
133 boost::system::error_code error;
134 boost::beast::get_lowest_layer(stream_).expires_after(timeout_);
135 auto const bytesUsed = stream_.async_handshake(
136 boost::asio::ssl::stream_base::server, buffer_.cdata(), yield[error]
139 return std::unexpected{error};
141 buffer_.consume(bytesUsed);
152 std::expected<void, Error>
154 boost::beast::http::response<boost::beast::http::string_body> response,
155 boost::asio::yield_context yield
158 return sendingQueue_.send(std::move(response), yield);
162 setTimeout(std::chrono::steady_clock::duration newTimeout)
override
164 timeout_ = newTimeout;
167 std::expected<void, Error>
170 auto httpResponse = std::move(response).intoHttpResponse();
171 return sendRaw(std::move(httpResponse), yield);
174 std::expected<Request, Error>
175 receive(boost::asio::yield_context yield)
override
177 if (request_.has_value()) {
178 Request result{std::move(request_).value()};
182 auto expectedRequest = fetch(yield);
183 if (expectedRequest.has_value())
184 return Request{std::move(expectedRequest).value()};
186 return std::unexpected{std::move(expectedRequest).error()};
190 close(boost::asio::yield_context yield)
override
199 [[maybe_unused]] boost::system::error_code error;
201 boost::beast::get_lowest_layer(stream_).expires_after(timeout_);
202 stream_.async_shutdown(yield[error]);
204 boost::beast::get_lowest_layer(stream_).socket().shutdown(
205 boost::asio::ip::tcp::socket::shutdown_type::shutdown_both, error
209 std::expected<bool, Error>
210 isUpgradeRequested(boost::asio::yield_context yield)
override
212 auto expectedRequest = fetch(yield);
213 if (not expectedRequest.has_value())
214 return std::unexpected{std::move(expectedRequest).error()};
216 request_ = std::move(expectedRequest).value();
218 return boost::beast::websocket::is_upgrade(request_.value());
221 std::expected<ConnectionPtr, Error>
224 boost::asio::yield_context yield
227 ASSERT(request_.has_value(),
"Request must be present to upgrade the connection");
229 return makeWsConnection(
233 std::move(request_).value(),
240 std::expected<boost::beast::http::request<boost::beast::http::string_body>, Error>
241 fetch(boost::asio::yield_context yield)
243 boost::beast::http::request<boost::beast::http::string_body> request{};
244 boost::system::error_code error;
245 boost::beast::get_lowest_layer(stream_).expires_after(timeout_);
246 boost::beast::http::async_read(stream_, buffer_, request, yield[error]);
248 return std::unexpected{error};