diff options
| author | zousar <[email protected]> | 2021-11-26 08:23:41 -0700 |
|---|---|---|
| committer | GitHub <[email protected]> | 2021-11-26 08:23:41 -0700 |
| commit | 39e30216589b20da3a400d4252e8530cfe4b148e (patch) | |
| tree | 9dd38fec2cf52fbd134ac6e5b3b1e522337384fb | |
| parent | Added .gdb_history to .gitignore (diff) | |
| parent | Address review feedback. (diff) | |
| download | zen-39e30216589b20da3a400d4252e8530cfe4b148e.tar.xz zen-39e30216589b20da3a400d4252e8530cfe4b148e.zip | |
Merge pull request #28 from EpicGames/non-elevated-asio
ASIO Mode Fixes
| -rw-r--r-- | zenhttp/httpasio.cpp | 51 | ||||
| -rw-r--r-- | zenhttp/httpserver.cpp | 81 | ||||
| -rw-r--r-- | zenhttp/httpsys.cpp | 79 | ||||
| -rw-r--r-- | zenhttp/include/zenhttp/httpserver.h | 2 |
4 files changed, 124 insertions, 89 deletions
diff --git a/zenhttp/httpasio.cpp b/zenhttp/httpasio.cpp index d5fe9adbb..b9db108db 100644 --- a/zenhttp/httpasio.cpp +++ b/zenhttp/httpasio.cpp @@ -15,6 +15,14 @@ ZEN_THIRD_PARTY_INCLUDES_START #include <asio.hpp> ZEN_THIRD_PARTY_INCLUDES_END +#define ASIO_VERBOSE_TRACE 0 + +#if ASIO_VERBOSE_TRACE +#define ZEN_TRACE_VERBOSE ZEN_TRACE +#else +#define ZEN_TRACE_VERBOSE(fmtstr, ...) +#endif + namespace zen::asio_http { using namespace std::literals; @@ -318,6 +326,7 @@ private: std::unique_ptr<asio::ip::tcp::socket> m_Socket; std::atomic<uint32_t> m_RequestCounter{0}; uint32_t m_ConnectionId = 0; + Ref<IHttpPackageHandler> m_PackageHandler; RwLock m_ResponsesLock; std::deque<std::unique_ptr<HttpResponse>> m_Responses; @@ -330,12 +339,12 @@ HttpServerConnection::HttpServerConnection(HttpAsioServerImpl& Server, std::uniq , m_Socket(std::move(Socket)) , m_ConnectionId(g_ConnectionIdCounter.fetch_add(1)) { - ZEN_TRACE("new connection #{}", m_ConnectionId); + ZEN_TRACE_VERBOSE("new connection #{}", m_ConnectionId); } HttpServerConnection::~HttpServerConnection() { - ZEN_TRACE("destroying connection #{}", m_ConnectionId); + ZEN_TRACE_VERBOSE("destroying connection #{}", m_ConnectionId); } void @@ -371,18 +380,18 @@ HttpServerConnection::EnqueueRead() asio::async_read(*m_Socket.get(), m_RequestBuffer, - asio::transfer_at_least(16), + asio::transfer_at_least(1), [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) +HttpServerConnection::OnDataReceived(const asio::error_code& Ec, [[maybe_unused]] std::size_t ByteCount) { if (Ec) { if (m_RequestState == RequestState::kDone || m_RequestState == RequestState::kInitialRead) { - ZEN_TRACE("on data received ERROR (EXPECTED), connection '{}' reason '{}'", m_ConnectionId, Ec.message()); + ZEN_TRACE_VERBOSE("on data received ERROR (EXPECTED), connection '{}' reason '{}'", m_ConnectionId, Ec.message()); return; } else @@ -392,7 +401,7 @@ HttpServerConnection::OnDataReceived(const asio::error_code& Ec, std::size_t Byt } } - ZEN_TRACE("on data received, connection '{}', request '{}', thread '{}', bytes '{}'", + ZEN_TRACE_VERBOSE("on data received, connection '{}', request '{}', thread '{}', bytes '{}'", m_ConnectionId, m_RequestCounter.load(std::memory_order_relaxed), GetCurrentThreadId(), @@ -421,7 +430,7 @@ 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) +HttpServerConnection::OnResponseDataSent(const asio::error_code& Ec, [[maybe_unused]] std::size_t ByteCount, bool Pop) { if (Ec) { @@ -430,7 +439,7 @@ HttpServerConnection::OnResponseDataSent(const asio::error_code& Ec, std::size_t } else { - ZEN_TRACE("on data sent, connection '{}', request '{}', thread '{}', bytes '{}'", + ZEN_TRACE_VERBOSE("on data sent, connection '{}', request '{}', thread '{}', bytes '{}'", m_ConnectionId, m_RequestCounter.load(std::memory_order_relaxed), GetCurrentThreadId(), @@ -485,9 +494,13 @@ HttpServerConnection::HandleRequest() { HttpAsioServerRequest Request(m_RequestData, *Service, m_RequestData.Body()); - ZEN_TRACE("handle request, connection '{}' request '{}'", m_ConnectionId, m_RequestCounter.load(std::memory_order_relaxed)); - Service->HandleRequest(Request); + ZEN_TRACE_VERBOSE("handle request, connection '{}' request '{}'", m_ConnectionId, m_RequestCounter.load(std::memory_order_relaxed)); + + if (!HandlePackageOffers(*Service, Request, m_PackageHandler)) + { + Service->HandleRequest(Request); + } if (std::unique_ptr<HttpResponse> Response = std::move(Request.m_Response)) { @@ -935,7 +948,7 @@ HttpAsioServerRequest::HttpAsioServerRequest(asio_http::HttpRequest& Request, Ht const int PrefixLength = Service.UriPrefixLength(); std::string_view Uri = Request.Url(); - Uri.remove_prefix(PrefixLength); + Uri.remove_prefix(std::min(PrefixLength, static_cast<int>(Uri.size()))); m_Uri = Uri; m_QueryString = Request.QueryString(); @@ -1099,6 +1112,10 @@ HttpAsioServerImpl::RegisterService(const char* InUrlPath, HttpService& Service) { std::string_view UrlPath(InUrlPath); Service.SetUriPrefixLength(UrlPath.size()); + if (!UrlPath.empty() && UrlPath.back() == '/') + { + UrlPath.remove_suffix(1); + } RwLock::ExclusiveLockScope _(m_Lock); m_UriHandlers.push_back({std::string(UrlPath), &Service}); @@ -1109,16 +1126,22 @@ HttpAsioServerImpl::RouteRequest(std::string_view Url) { RwLock::SharedLockScope _(m_Lock); + HttpService* CandidateService = nullptr; + std::string::size_type CandidateMatchSize = 0; for (const ServiceEntry& SvcEntry : m_UriHandlers) { const std::string& SvcUrl = SvcEntry.ServiceUrlPath; - if (Url.compare(0, SvcUrl.size(), SvcUrl) == 0) + const std::string::size_type SvcUrlSize = SvcUrl.size(); + if ((SvcUrlSize >= CandidateMatchSize) && + Url.compare(0, SvcUrlSize, SvcUrl) == 0 && + ((SvcUrlSize == Url.size()) || (Url[SvcUrlSize] == '/'))) { - return SvcEntry.Service; + CandidateMatchSize = SvcUrl.size(); + CandidateService = SvcEntry.Service; } } - return nullptr; + return CandidateService; } } // namespace zen::asio_http diff --git a/zenhttp/httpserver.cpp b/zenhttp/httpserver.cpp index f40836c4a..7486e82e1 100644 --- a/zenhttp/httpserver.cpp +++ b/zenhttp/httpserver.cpp @@ -7,6 +7,7 @@ #include "httpsys.h" #include <zencore/compactbinary.h> +#include <zencore/compactbinarybuilder.h> #include <zencore/compactbinarypackage.h> #include <zencore/iobuffer.h> #include <zencore/logging.h> @@ -619,6 +620,86 @@ CreateHttpServer(std::string_view ServerClass) ////////////////////////////////////////////////////////////////////////// +bool +HandlePackageOffers(HttpService& Service, HttpServerRequest& Request, Ref<IHttpPackageHandler>& PackageHandlerRef) +{ + if (Request.RequestVerb() == HttpVerb::kPost) + { + if (Request.RequestContentType() == HttpContentType::kCbPackageOffer) + { + // The client is presenting us with a package attachments offer, we need + // to filter it down to the list of attachments we need them to send in + // the follow-up request + + PackageHandlerRef = Service.HandlePackageRequest(Request); + + if (PackageHandlerRef) + { + CbObject OfferMessage = LoadCompactBinaryObject(Request.ReadPayload()); + + std::vector<IoHash> OfferCids; + + for (auto& CidEntry : OfferMessage["offer"]) + { + if (!CidEntry.IsHash()) + { + // Should yield bad request response? + + ZEN_WARN("found invalid entry in offer"); + + continue; + } + + OfferCids.push_back(CidEntry.AsHash()); + } + + ZEN_TRACE("request #{} -> filtering offer of {} entries", Request.RequestId(), OfferCids.size()); + + PackageHandlerRef->FilterOffer(OfferCids); + + ZEN_TRACE("request #{} -> filtered to {} entries", Request.RequestId(), OfferCids.size()); + + CbObjectWriter ResponseWriter; + ResponseWriter.BeginArray("need"); + + for (const IoHash& Cid : OfferCids) + { + ResponseWriter.AddHash(Cid); + } + + ResponseWriter.EndArray(); + + // Emit filter response + Request.WriteResponse(HttpResponseCode::OK, ResponseWriter.Save()); + return true; + } + } + else if (Request.RequestContentType() == HttpContentType::kCbPackage) + { + // Process chunks in package request + + PackageHandlerRef = Service.HandlePackageRequest(Request); + + // TODO: this should really be done in a streaming fashion, currently this emulates + // the intended flow from an API perspective + + if (PackageHandlerRef) + { + PackageHandlerRef->OnRequestBegin(); + + auto CreateBuffer = [&](const IoHash& Cid, uint64_t Size) -> IoBuffer { return PackageHandlerRef->CreateTarget(Cid, Size); }; + + CbPackage Package = ParsePackageMessage(Request.ReadPayload(), CreateBuffer); + + PackageHandlerRef->OnRequestComplete(); + } + } + } + return false; +} + +////////////////////////////////////////////////////////////////////////// + #if ZEN_WITH_TESTS TEST_CASE("http.common") diff --git a/zenhttp/httpsys.cpp b/zenhttp/httpsys.cpp index cdf9e0a39..15d7a9700 100644 --- a/zenhttp/httpsys.cpp +++ b/zenhttp/httpsys.cpp @@ -1131,83 +1131,12 @@ HttpSysTransaction::InvokeRequestHandler(HttpService& Service, IoBuffer Payload) { HttpSysServerRequest& ThisRequest = m_HandlerRequest.emplace(*this, Service, Payload); - if (ThisRequest.RequestVerb() == HttpVerb::kPost) - { - if (ThisRequest.RequestContentType() == HttpContentType::kCbPackageOffer) - { - // The client is presenting us with a package attachments offer, we need - // to filter it down to the list of attachments we need them to send in - // the follow-up request - - m_PackageHandler = Service.HandlePackageRequest(ThisRequest); - - if (m_PackageHandler) - { - CbObject OfferMessage = LoadCompactBinaryObject(Payload); - - std::vector<IoHash> OfferCids; - - for (auto& CidEntry : OfferMessage["offer"]) - { - if (!CidEntry.IsHash()) - { - // Should yield bad request response? - - ZEN_WARN("found invalid entry in offer"); - - continue; - } - - OfferCids.push_back(CidEntry.AsHash()); - } - - ZEN_TRACE("request #{} -> filtering offer of {} entries", ThisRequest.RequestId(), OfferCids.size()); - - m_PackageHandler->FilterOffer(OfferCids); - - ZEN_TRACE("request #{} -> filtered to {} entries", ThisRequest.RequestId(), OfferCids.size()); - - CbObjectWriter ResponseWriter; - ResponseWriter.BeginArray("need"); - - for (const IoHash& Cid : OfferCids) - { - ResponseWriter.AddHash(Cid); - } - - ResponseWriter.EndArray(); - - // Emit filter response - ThisRequest.WriteResponse(HttpResponseCode::OK, ResponseWriter.Save()); - - return ThisRequest; - } - } - else if (ThisRequest.RequestContentType() == HttpContentType::kCbPackage) - { - // Process chunks in package request - - m_PackageHandler = Service.HandlePackageRequest(ThisRequest); - - // TODO: this should really be done in a streaming fashion, currently this emulates - // the intended flow from an API perspective - - if (m_PackageHandler) - { - m_PackageHandler->OnRequestBegin(); - - auto CreateBuffer = [&](const IoHash& Cid, uint64_t Size) -> IoBuffer { return m_PackageHandler->CreateTarget(Cid, Size); }; - - CbPackage Package = ParsePackageMessage(ThisRequest.ReadPayload(), CreateBuffer); - - m_PackageHandler->OnRequestComplete(); - } - } - } - // Default request handling - Service.HandleRequest(ThisRequest); + if (!HandlePackageOffers(Service, ThisRequest, m_PackageHandler)) + { + Service.HandleRequest(ThisRequest); + } return ThisRequest; } diff --git a/zenhttp/include/zenhttp/httpserver.h b/zenhttp/include/zenhttp/httpserver.h index 93ba452c7..088028081 100644 --- a/zenhttp/include/zenhttp/httpserver.h +++ b/zenhttp/include/zenhttp/httpserver.h @@ -269,6 +269,8 @@ private: std::unordered_map<std::string, std::string> m_PatternMap; }; +bool HandlePackageOffers(HttpService& Service, HttpServerRequest& Request, Ref<IHttpPackageHandler>& PackageHandlerRef); + void http_forcelink(); // internal } // namespace zen |