diff options
| author | Martin Ridgers <[email protected]> | 2021-11-25 11:07:49 +0100 |
|---|---|---|
| committer | Martin Ridgers <[email protected]> | 2021-11-25 11:07:49 +0100 |
| commit | 594501a96a4b64d3832d844909172a33fa14e7e2 (patch) | |
| tree | 4e48156c975064f5edf32202e02e18b720f503b9 /zenhttp/httpasio.cpp | |
| parent | Tests for building ArgV for a fork-exec (diff) | |
| parent | Merge branch 'main' of https://github.com/EpicGames/zen (diff) | |
| download | zen-594501a96a4b64d3832d844909172a33fa14e7e2.tar.xz zen-594501a96a4b64d3832d844909172a33fa14e7e2.zip | |
Merged main
Diffstat (limited to 'zenhttp/httpasio.cpp')
| -rw-r--r-- | zenhttp/httpasio.cpp | 122 |
1 files changed, 60 insertions, 62 deletions
diff --git a/zenhttp/httpasio.cpp b/zenhttp/httpasio.cpp index d94f6af2e..0ed5e78cf 100644 --- a/zenhttp/httpasio.cpp +++ b/zenhttp/httpasio.cpp @@ -6,6 +6,7 @@ #include <zenhttp/httpserver.h> #include <deque> +#include <memory> #include <memory_resource> ZEN_THIRD_PARTY_INCLUDES_START @@ -171,7 +172,7 @@ private: IoBuffer m_BodyBuffer; uint64_t m_BodyPosition = 0; http_parser m_Parser; - char m_HeaderBuffer[512]; + char m_HeaderBuffer[1024]; void AppendInputBytes(const char* Data, size_t Bytes); void AppendCurrentHeader(); @@ -283,7 +284,7 @@ private: ////////////////////////////////////////////////////////////////////////// -struct HttpServerConnection +struct HttpServerConnection : std::enable_shared_from_this<HttpServerConnection> { HttpServerConnection(HttpAsioServerImpl& Server, std::unique_ptr<asio::ip::tcp::socket>&& Socket); ~HttpServerConnection(); @@ -292,6 +293,8 @@ struct HttpServerConnection void TerminateConnection(); void HandleRequest(); + std::shared_ptr<HttpServerConnection> AsSharedPtr() { return shared_from_this(); } + private: enum class RequestState { @@ -371,50 +374,32 @@ HttpServerConnection::EnqueueRead() asio::async_read(*m_Socket.get(), m_RequestBuffer, asio::transfer_at_least(16), - [this](const asio::error_code& Ec, std::size_t ByteCount) { - if (Ec) - { - if (m_RequestState == RequestState::kDone || m_RequestState == RequestState::kInitialRead) - { - // Expected, just silently handle the condition - // - // if we get an I/O error on the boundary between two messages - // it should be fine to just not say anything - - ZEN_TRACE("(expected) socket read error: conn#{} '{}'", m_ConnectionId, Ec.message()); - } - else - { - ZEN_WARN("unexpected socket read error: conn#{} {}", m_ConnectionId, Ec.message()); - } - - delete this; - } - else - { - ZEN_TRACE("read: conn#:{} seq#:{} t:{} bytes:{}", - m_ConnectionId, - m_RequestCounter.load(std::memory_order_relaxed), - zen::GetCurrentThreadId(), - ByteCount); - - OnDataReceived(Ec, ByteCount); - } - }); + [Conn = AsSharedPtr()](const asio::error_code& Ec, std::size_t ByteCount) { Conn->OnDataReceived(Ec, ByteCount); }); } void HttpServerConnection::OnDataReceived(const asio::error_code& Ec, std::size_t ByteCount) { - ZEN_UNUSED(ByteCount); - if (Ec) { - ZEN_ERROR("OnDataReceived Error: {}", Ec.message()); - - return OnError(); + if (m_RequestState == RequestState::kDone || m_RequestState == RequestState::kInitialRead) + { + ZEN_TRACE("on data received ERROR (EXPECTED), connection '{}' reason '{}'", m_ConnectionId, Ec.message()); + return; + } + else + { + ZEN_ERROR("on data received ERROR, connection '{}' reason '{}'", m_ConnectionId, Ec.message()); + return OnError(); + } } + ZEN_TRACE("on data received, connection '{}', request '{}', thread '{}', bytes '{}'", + m_ConnectionId, + m_RequestCounter.load(std::memory_order_relaxed), + zen::GetCurrentThreadId(), + NiceBytes(ByteCount)); + while (m_RequestBuffer.size()) { const asio::const_buffer& InputBuffer = m_RequestBuffer.data(); @@ -440,24 +425,34 @@ HttpServerConnection::OnDataReceived(const asio::error_code& Ec, std::size_t Byt void HttpServerConnection::OnResponseDataSent(const asio::error_code& Ec, std::size_t ByteCount, bool Pop) { - ZEN_UNUSED(ByteCount); if (Ec) { - ZEN_ERROR("OnResponseDataSent Error: {}", Ec.message()); - return OnError(); + ZEN_ERROR("on data sent ERROR, connection '{}' reason '{}'", m_ConnectionId, Ec.message()); + OnError(); } else { + ZEN_TRACE("on data sent, connection '{}', request '{}', thread '{}', bytes '{}'", + m_ConnectionId, + m_RequestCounter.load(std::memory_order_relaxed), + zen::GetCurrentThreadId(), + NiceBytes(ByteCount)); + if (!m_RequestData.IsKeepAlive()) { m_RequestState = RequestState::kDone; m_Socket->close(); } - else if (Pop) + else { - RwLock::ExclusiveLockScope _(m_ResponsesLock); - m_Responses.pop_front(); + if (Pop) + { + RwLock::ExclusiveLockScope _(m_ResponsesLock); + m_Responses.pop_front(); + } + + m_RequestCounter.fetch_add(1); } } } @@ -480,7 +475,7 @@ HttpServerConnection::HandleRequest() if (Ec) { - ZEN_WARN("socket shutdown reported error: {}", Ec.message()); + ZEN_WARN("socket shutdown ERROR, reason '{}'", Ec.message()); } } else @@ -488,14 +483,11 @@ HttpServerConnection::HandleRequest() m_RequestState = RequestState::kWriting; } - const uint32_t RequestNum = m_RequestCounter.load(std::memory_order_relaxed); - m_RequestCounter.fetch_add(1); - if (HttpService* Service = m_Server.RouteRequest(m_RequestData.Url())) { HttpAsioServerRequest Request(m_RequestData, *Service, m_RequestData.Body()); - ZEN_TRACE("Handling request: Conn#{} Req#{}", m_ConnectionId, RequestNum); + ZEN_TRACE("handle request, connection '{}' request '{}'", m_ConnectionId, m_RequestCounter.load(std::memory_order_relaxed)); Service->HandleRequest(Request); @@ -527,9 +519,8 @@ HttpServerConnection::HandleRequest() asio::async_write(*m_Socket.get(), ResponseBuffers, asio::transfer_exactly(ResponseLength), - [this, RequestNum](const asio::error_code& Ec, std::size_t ByteCount) { - ZEN_TRACE("Response sent: Conn#{} Req#{} ({})", m_ConnectionId, RequestNum, NiceBytes(ByteCount)); - OnResponseDataSent(Ec, ByteCount, true); + [Conn = AsSharedPtr()](const asio::error_code& Ec, std::size_t ByteCount) { + Conn->OnResponseDataSent(Ec, ByteCount, true); }); return; @@ -550,9 +541,10 @@ HttpServerConnection::HandleRequest() "\r\n"sv; } - asio::async_write(*m_Socket.get(), asio::buffer(Response), [this](const asio::error_code& Ec, std::size_t ByteCount) { - OnResponseDataSent(Ec, ByteCount); - }); + asio::async_write( + *m_Socket.get(), + asio::buffer(Response), + [Conn = AsSharedPtr()](const asio::error_code& Ec, std::size_t ByteCount) { Conn->OnResponseDataSent(Ec, ByteCount); }); } else { @@ -574,9 +566,10 @@ HttpServerConnection::HandleRequest() "No suitable route found"sv; } - asio::async_write(*m_Socket.get(), asio::buffer(Response), [this](const asio::error_code& Ec, std::size_t ByteCount) { - OnResponseDataSent(Ec, ByteCount); - }); + asio::async_write( + *m_Socket.get(), + asio::buffer(Response), + [Conn = AsSharedPtr()](const asio::error_code& Ec, std::size_t ByteCount) { Conn->OnResponseDataSent(Ec, ByteCount); }); } } @@ -877,8 +870,13 @@ struct HttpAcceptor HttpAcceptor(HttpAsioServerImpl& Server, asio::io_service& IoService, uint16_t Port) : m_Server(Server) , m_IoService(IoService) - , m_Acceptor(m_IoService, asio::ip::tcp::endpoint(asio::ip::address_v4::any(), Port)) + , m_Acceptor(m_IoService, asio::ip::tcp::v6()) { + m_Acceptor.set_option(asio::ip::v6_only(false)); + m_Acceptor.set_option(asio::socket_base::reuse_address(true)); + m_Acceptor.set_option(asio::ip::tcp::no_delay(true)); + m_Acceptor.bind(asio::ip::tcp::endpoint(asio::ip::address_v6::any(), Port)); + m_Acceptor.listen(); } void Start() @@ -902,14 +900,14 @@ struct HttpAcceptor else { // New connection established, pass socket ownership into connection object - // and initiate request handling loop + // and initiate request handling loop. The connection lifetime is + // managed by the async read/write loop by passing the shared + // reference to the callbacks. Socket->set_option(asio::ip::tcp::no_delay(true)); - HttpServerConnection* Conn = new HttpServerConnection(m_Server, std::move(Socket)); + auto Conn = std::make_shared<HttpServerConnection>(m_Server, std::move(Socket)); Conn->HandleNewRequest(); - - // note: the connection object is responsible for deleting itself } if (!m_IsStopped.load()) |