#include #include "HttpSession.h" #include "WebsocketSession.h" #include "./../endpoints_handlers/HandleRequest.h" namespace uad { HttpSession::Queue::Queue(HttpSession& self) : self_(self) { static_assert(limit > 0, "Queue limit must be positive"); items_.reserve(limit); } bool HttpSession::Queue::IsFull() const { return items_.size() >= limit; } bool HttpSession::Queue::OnWrite() { BOOST_ASSERT(!items_.empty()); auto const was_full = IsFull(); items_.erase(items_.begin()); if (!items_.empty()) (*items_.front())(); return was_full; } HttpSession::HttpSession(boost::asio::ip::tcp::socket&& socket, std::shared_ptr const& doc_root) : stream_(std::move(socket)), doc_root_(doc_root), queue_(*this) { } void HttpSession::Run() { boost::asio::dispatch( stream_.get_executor(), boost::beast::bind_front_handler(&HttpSession::DoRead, this->shared_from_this())); } void HttpSession::DoRead() { parser_.emplace(); parser_->body_limit(10000); stream_.expires_after(std::chrono::seconds(30)); boost::beast::http::async_read( stream_, buffer_, *parser_, boost::beast::bind_front_handler(&HttpSession::OnRead, shared_from_this())); } void HttpSession::OnRead(boost::beast::error_code ec, std::size_t bytes_transferred) { boost::ignore_unused(bytes_transferred); if (ec == boost::beast::http::error::end_of_stream) return DoClose(); if (ec) return Fail(ec, "read"); if (boost::beast::websocket::is_upgrade(parser_->get())) { std::make_shared(stream_.release_socket())->DoAccept(parser_->release()); return; } HandleRequest(*doc_root_, parser_->release(), queue_); if (!queue_.IsFull()) DoRead(); } void HttpSession::OnWrite(bool close, boost::beast::error_code ec, std::size_t bytes_transferred) { boost::ignore_unused(bytes_transferred); if (ec) return Fail(ec, "write"); if (close) { return DoClose(); } if (queue_.OnWrite()) { DoRead(); } } void HttpSession::DoClose() { boost::beast::error_code ec; stream_.socket().shutdown(boost::asio::ip::tcp::socket::shutdown_send, ec); } } // namespace uad