diff options
| author | Martin Ridgers <[email protected]> | 2021-09-16 10:13:28 +0200 |
|---|---|---|
| committer | Martin Ridgers <[email protected]> | 2021-09-16 10:13:58 +0200 |
| commit | 7aa3ceabe4254479bd066ae3ea941396fdc6733c (patch) | |
| tree | a7d0a7fde0a5a3c42302238965c25c665fc28005 /zenhttp | |
| parent | Missing include (diff) | |
| parent | Added some placeholder HttpClient functions to be fleshed out (diff) | |
| download | zen-7aa3ceabe4254479bd066ae3ea941396fdc6733c.tar.xz zen-7aa3ceabe4254479bd066ae3ea941396fdc6733c.zip | |
Merge from main
Diffstat (limited to 'zenhttp')
| -rw-r--r-- | zenhttp/httpclient.cpp | 25 | ||||
| -rw-r--r-- | zenhttp/httpserver.cpp | 106 | ||||
| -rw-r--r-- | zenhttp/httpsys.cpp | 30 | ||||
| -rw-r--r-- | zenhttp/include/zenhttp/httpclient.h | 10 | ||||
| -rw-r--r-- | zenhttp/include/zenhttp/httpcommon.h | 4 | ||||
| -rw-r--r-- | zenhttp/include/zenhttp/httpserver.h | 4 | ||||
| -rw-r--r-- | zenhttp/include/zenhttp/zenhttp.h | 6 | ||||
| -rw-r--r-- | zenhttp/zenhttp.cpp | 13 | ||||
| -rw-r--r-- | zenhttp/zenhttp.vcxproj | 1 | ||||
| -rw-r--r-- | zenhttp/zenhttp.vcxproj.filters | 1 |
10 files changed, 143 insertions, 57 deletions
diff --git a/zenhttp/httpclient.cpp b/zenhttp/httpclient.cpp index b7df12026..7e3e9d374 100644 --- a/zenhttp/httpclient.cpp +++ b/zenhttp/httpclient.cpp @@ -7,6 +7,7 @@ #include <zencore/compactbinarypackage.h> #include <zencore/iobuffer.h> #include <zencore/logging.h> +#include <zencore/session.h> #include <zencore/sharedbuffer.h> #include <zencore/stream.h> @@ -30,6 +31,9 @@ FromCprResponse(cpr::Response& InResponse) HttpClient::HttpClient(std::string_view BaseUri) : m_BaseUri(BaseUri) { + StringBuilder<32> SessionId; + GetSessionId().ToString(SessionId); + m_SessionId = SessionId; } HttpClient::~HttpClient() @@ -68,8 +72,7 @@ HttpClient::TransactPackage(std::string_view Url, CbPackage Package) BinaryWriter MemWriter(MemOut); Writer.Save(MemWriter); - Sess.SetHeader( - {{"Content-Type", "application/x-ue-offer"}, {"UE-Session", "123456789012345678901234"}, {"UE-Request", RequestIdString}}); + Sess.SetHeader({{"Content-Type", "application/x-ue-offer"}, {"UE-Session", m_SessionId}, {"UE-Request", RequestIdString}}); Sess.SetBody(cpr::Body{(const char*)MemOut.Data(), MemOut.Size()}); cpr::Response FilterResponse = Sess.Post(); @@ -111,8 +114,7 @@ HttpClient::TransactPackage(std::string_view Url, CbPackage Package) CompositeBuffer Message = FormatPackageMessageBuffer(SendPackage); SharedBuffer FlatMessage = Message.Flatten(); - Sess.SetHeader( - {{"Content-Type", "application/x-ue-cbpkg"}, {"UE-Session", "123456789012345678901234"}, {"UE-Request", RequestIdString}}); + Sess.SetHeader({{"Content-Type", "application/x-ue-cbpkg"}, {"UE-Session", m_SessionId}, {"UE-Request", RequestIdString}}); Sess.SetBody(cpr::Body{(const char*)FlatMessage.GetData(), FlatMessage.GetSize()}); cpr::Response FilterResponse = Sess.Post(); @@ -135,6 +137,21 @@ HttpClient::TransactPackage(std::string_view Url, CbPackage Package) } HttpClient::Response +HttpClient::Put(std::string_view Url, IoBuffer Payload) +{ + ZEN_UNUSED(Url); + ZEN_UNUSED(Payload); + return {}; +} + +HttpClient::Response +HttpClient::Get(std::string_view Url) +{ + ZEN_UNUSED(Url); + return {}; +} + +HttpClient::Response HttpClient::Delete(std::string_view Url) { ZEN_UNUSED(Url); diff --git a/zenhttp/httpserver.cpp b/zenhttp/httpserver.cpp index f97ac0067..f4a5f4345 100644 --- a/zenhttp/httpserver.cpp +++ b/zenhttp/httpserver.cpp @@ -19,6 +19,7 @@ #include <conio.h> #include <new.h> #include <charconv> +#include <mutex> #include <span> #include <string_view> @@ -53,59 +54,81 @@ MapContentTypeToString(HttpContentType ContentType) case HttpContentType::kCbPackageOffer: return "application/x-ue-offer"sv; + case HttpContentType::kCompressedBinary: + return "application/x-ue-comp"sv; + case HttpContentType::kYAML: return "text/yaml"sv; } } -static const uint32_t HashBinary = HashStringDjb2("application/octet-stream"sv); -static const uint32_t HashJson = HashStringDjb2("application/json"sv); -static const uint32_t HashYaml = HashStringDjb2("text/yaml"sv); -static const uint32_t HashText = HashStringDjb2("text/plain"sv); -static const uint32_t HashCompactBinary = HashStringDjb2("application/x-ue-cb"sv); -static const uint32_t HashCompactBinaryPackage = HashStringDjb2("application/x-ue-cbpkg"sv); -static const uint32_t HashCompactBinaryPackageOffer = HashStringDjb2("application/x-ue-offer"sv); +////////////////////////////////////////////////////////////////////////// + +static constinit uint32_t HashBinary = HashStringDjb2("application/octet-stream"sv); +static constinit uint32_t HashJson = HashStringDjb2("application/json"sv); +static constinit uint32_t HashYaml = HashStringDjb2("text/yaml"sv); +static constinit uint32_t HashText = HashStringDjb2("text/plain"sv); +static constinit uint32_t HashCompactBinary = HashStringDjb2("application/x-ue-cb"sv); +static constinit uint32_t HashCompactBinaryPackage = HashStringDjb2("application/x-ue-cbpkg"sv); +static constinit uint32_t HashCompactBinaryPackageOffer = HashStringDjb2("application/x-ue-offer"sv); +static constinit uint32_t HashCompressedBinary = HashStringDjb2("application/x-ue-comp"sv); + +std::once_flag InitContentTypeLookup; + +struct HashedTypeEntry +{ + uint32_t Hash; + HttpContentType Type; +} TypeHashTable[] = {{HashBinary, HttpContentType::kBinary}, + {HashCompactBinary, HttpContentType::kCbObject}, + {HashCompactBinaryPackage, HttpContentType::kCbPackage}, + {HashCompactBinaryPackageOffer, HttpContentType::kCbPackageOffer}, + {HashJson, HttpContentType::kJSON}, + {HashYaml, HttpContentType::kYAML}, + {HashText, HttpContentType::kText}, + {HashCompressedBinary, HttpContentType::kCompressedBinary}}; HttpContentType -ParseContentType(const std::string_view& ContentTypeString) +ParseContentTypeImpl(const std::string_view& ContentTypeString) { if (!ContentTypeString.empty()) { const uint32_t CtHash = HashStringDjb2(ContentTypeString); - if (CtHash == HashBinary) - { - return HttpContentType::kBinary; - } - else if (CtHash == HashCompactBinary) - { - return HttpContentType::kCbObject; - } - else if (CtHash == HashCompactBinaryPackage) + if (auto It = std::lower_bound(std::begin(TypeHashTable), + std::end(TypeHashTable), + CtHash, + [](const HashedTypeEntry& Lhs, const uint32_t Rhs) { return Lhs.Hash < Rhs; }); + It != std::end(TypeHashTable)) { - return HttpContentType::kCbPackage; - } - else if (CtHash == HashCompactBinaryPackageOffer) - { - return HttpContentType::kCbPackageOffer; - } - else if (CtHash == HashJson) - { - return HttpContentType::kJSON; - } - else if (CtHash == HashYaml) - { - return HttpContentType::kYAML; - } - else if (CtHash == HashText) - { - return HttpContentType::kText; + if (It->Hash == CtHash) + { + return It->Type; + } } } return HttpContentType::kUnknownContentType; } +HttpContentType +ParseContentTypeInit(const std::string_view& ContentTypeString) +{ + std::call_once(InitContentTypeLookup, [] { + std::sort(std::begin(TypeHashTable), std::end(TypeHashTable), [](const HashedTypeEntry& Lhs, const HashedTypeEntry& Rhs) { + return Lhs.Hash < Rhs.Hash; + }); + }); + + ParseContentType = ParseContentTypeImpl; + + return ParseContentTypeImpl(ContentTypeString); +} + +HttpContentType (*ParseContentType)(const std::string_view& ContentTypeString) = &ParseContentTypeInit; + +////////////////////////////////////////////////////////////////////////// + const char* ReasonStringForHttpResultCode(int HttpCode) { @@ -502,7 +525,7 @@ CreateHttpServer() ////////////////////////////////////////////////////////////////////////// -TEST_CASE("http") +TEST_CASE("http.common") { using namespace std::literals; @@ -523,6 +546,19 @@ TEST_CASE("http") // TestHttpServerRequest req{}; // r.HandleRequest(req); } + + SUBCASE("content-type") + { + for (uint8_t i = 0; i < uint8_t(HttpContentType::kCOUNT); ++i) + { + HttpContentType Ct{i}; + + if (Ct != HttpContentType::kUnknownContentType) + { + CHECK_EQ(Ct, ParseContentType(MapContentTypeToString(Ct))); + } + } + } } void diff --git a/zenhttp/httpsys.cpp b/zenhttp/httpsys.cpp index 533971c4c..d4c58bffd 100644 --- a/zenhttp/httpsys.cpp +++ b/zenhttp/httpsys.cpp @@ -554,7 +554,7 @@ HttpMessageResponseRequest::IssueRequest(std::error_code& ErrorCode) CancelThreadpoolIo(Iocp); - ZEN_ERROR("failed to send HTTP response (error: '{}'), request URL: {}"sv, SendResult, HttpReq->pRawUrl); + ZEN_ERROR("failed to send HTTP response (error: '{}'), request URL: {}", SendResult, HttpReq->pRawUrl); ErrorCode = MakeErrorCode(SendResult); } @@ -605,7 +605,7 @@ HttpSysServer::Initialize(const wchar_t* UrlPath) if (Result != NO_ERROR) { - ZEN_ERROR("Failed to create server session for '{}': {x}"sv, WideToUtf8(UrlPath), Result); + ZEN_ERROR("Failed to create server session for '{}': {:#x}", WideToUtf8(UrlPath), Result); return; } @@ -614,7 +614,7 @@ HttpSysServer::Initialize(const wchar_t* UrlPath) if (Result != NO_ERROR) { - ZEN_ERROR("Failed to create URL group for '{}': {x}"sv, WideToUtf8(UrlPath), Result); + ZEN_ERROR("Failed to create URL group for '{}': {:#x}", WideToUtf8(UrlPath), Result); return; } @@ -625,7 +625,7 @@ HttpSysServer::Initialize(const wchar_t* UrlPath) if (Result != NO_ERROR) { - ZEN_ERROR("Failed to add base URL to URL group for '{}': {x}"sv, WideToUtf8(UrlPath), Result); + ZEN_ERROR("Failed to add base URL to URL group for '{}': {:#x}", WideToUtf8(UrlPath), Result); return; } @@ -640,7 +640,7 @@ HttpSysServer::Initialize(const wchar_t* UrlPath) if (Result != NO_ERROR) { - ZEN_ERROR("Failed to create request queue for '{}': {x}"sv, WideToUtf8(UrlPath), Result); + ZEN_ERROR("Failed to create request queue for '{}': {:#x}", WideToUtf8(UrlPath), Result); return; } @@ -652,7 +652,7 @@ HttpSysServer::Initialize(const wchar_t* UrlPath) if (Result != NO_ERROR) { - ZEN_ERROR("Failed to set server binding property for '{}': {x}"sv, WideToUtf8(UrlPath), Result); + ZEN_ERROR("Failed to set server binding property for '{}': {:#x}", WideToUtf8(UrlPath), Result); return; } @@ -664,7 +664,7 @@ HttpSysServer::Initialize(const wchar_t* UrlPath) if (ErrorCode) { - ZEN_ERROR("Failed to create IOCP for '{}': {}"sv, WideToUtf8(UrlPath), ErrorCode.message()); + ZEN_ERROR("Failed to create IOCP for '{}': {}", WideToUtf8(UrlPath), ErrorCode.message()); } else { @@ -803,7 +803,7 @@ HttpSysServer::RegisterService(const char* UrlPath, HttpService& Service) if (Result != NO_ERROR) { - ZEN_ERROR("HttpAddUrlToUrlGroup failed with result {}"sv, Result); + ZEN_ERROR("HttpAddUrlToUrlGroup failed with result {}", Result); return; } @@ -829,7 +829,7 @@ HttpSysServer::UnregisterService(const char* UrlPath, HttpService& Service) if (Result != NO_ERROR) { - ZEN_ERROR("HttpRemoveUrlFromUrlGroup failed with result {}"sv, Result); + ZEN_ERROR("HttpRemoveUrlFromUrlGroup failed with result {}", Result); } } @@ -917,7 +917,7 @@ HttpSysTransaction::HandleCompletion(ULONG IoResult, ULONG_PTR NumberOfBytesTran if (ErrorCode) { - ZEN_ERROR("IssueRequest() failed {}"sv, ErrorCode.message()); + ZEN_ERROR("IssueRequest() failed {}", ErrorCode.message()); } else { @@ -926,7 +926,7 @@ HttpSysTransaction::HandleCompletion(ULONG IoResult, ULONG_PTR NumberOfBytesTran } catch (std::exception& Ex) { - ZEN_ERROR("exception caught from IssueRequest(): {}"sv, Ex.what()); + ZEN_ERROR("exception caught from IssueRequest(): {}", Ex.what()); // something went wrong, no request is pending } @@ -980,14 +980,20 @@ HttpSysTransaction::InvokeRequestHandler(HttpService& Service, IoBuffer Payload) { // Should yield bad request response? + ZEN_WARN("found invalid entry in offer"); + continue; } - OfferCids.push_back(CidEntry.AsHash(IoHash::Zero)); + 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"); diff --git a/zenhttp/include/zenhttp/httpclient.h b/zenhttp/include/zenhttp/httpclient.h index 8975f6fe1..3e342f2bd 100644 --- a/zenhttp/include/zenhttp/httpclient.h +++ b/zenhttp/include/zenhttp/httpclient.h @@ -5,6 +5,7 @@ #include "zenhttp.h" #include <zencore/iobuffer.h> +#include <zencore/uid.h> #include <zenhttp/httpcommon.h> #include <zencore/windows.h> @@ -22,7 +23,9 @@ namespace zen { class CbPackage; -/** Asynchronous HTTP client implementation for Zen use cases +/** HTTP client implementation for Zen use cases + + Currently simple and synchronous, should become lean and asynchronous */ class HttpClient { @@ -33,14 +36,17 @@ public: struct Response { int StatusCode = 0; - IoBuffer ResponsePayload; + IoBuffer ResponsePayload; // Note: this also includes the content type }; + [[nodiscard]] Response Put(std::string_view Url, IoBuffer Payload); + [[nodiscard]] Response Get(std::string_view Url); [[nodiscard]] Response TransactPackage(std::string_view Url, CbPackage Package); [[nodiscard]] Response Delete(std::string_view Url); private: std::string m_BaseUri; + std::string m_SessionId; }; } // namespace zen diff --git a/zenhttp/include/zenhttp/httpcommon.h b/zenhttp/include/zenhttp/httpcommon.h index 41ec706f4..08f1b47a9 100644 --- a/zenhttp/include/zenhttp/httpcommon.h +++ b/zenhttp/include/zenhttp/httpcommon.h @@ -18,8 +18,8 @@ class CbPackage; class StringBuilderBase; std::string_view MapContentTypeToString(HttpContentType ContentType); -HttpContentType ParseContentType(const std::string_view& ContentTypeString); -const char* ReasonStringForHttpResultCode(int HttpCode); +extern HttpContentType (*ParseContentType)(const std::string_view& ContentTypeString); +const char* ReasonStringForHttpResultCode(int HttpCode); [[nodiscard]] inline bool IsHttpSuccessCode(int HttpCode) diff --git a/zenhttp/include/zenhttp/httpserver.h b/zenhttp/include/zenhttp/httpserver.h index de097ceb3..f656c69a8 100644 --- a/zenhttp/include/zenhttp/httpserver.h +++ b/zenhttp/include/zenhttp/httpserver.h @@ -268,6 +268,6 @@ private: std::unordered_map<std::string, std::string> m_PatternMap; }; -} // namespace zen - void http_forcelink(); // internal + +} // namespace zen diff --git a/zenhttp/include/zenhttp/zenhttp.h b/zenhttp/include/zenhttp/zenhttp.h index c6ec92e7c..586fc98b4 100644 --- a/zenhttp/include/zenhttp/zenhttp.h +++ b/zenhttp/include/zenhttp/zenhttp.h @@ -5,3 +5,9 @@ #include <zencore/zencore.h> #define ZENHTTP_API // Placeholder to allow DLL configs in the future + +namespace zen { + + ZENHTTP_API void zenhttp_forcelinktests(); + +} diff --git a/zenhttp/zenhttp.cpp b/zenhttp/zenhttp.cpp new file mode 100644 index 000000000..148cf4499 --- /dev/null +++ b/zenhttp/zenhttp.cpp @@ -0,0 +1,13 @@ +#include <zenhttp/zenhttp.h> + +#include <zenhttp/httpserver.h> + +namespace zen { + +void +zenhttp_forcelinktests() +{ + http_forcelink(); +} + +}
\ No newline at end of file diff --git a/zenhttp/zenhttp.vcxproj b/zenhttp/zenhttp.vcxproj index 3536d1929..eca9898d3 100644 --- a/zenhttp/zenhttp.vcxproj +++ b/zenhttp/zenhttp.vcxproj @@ -100,6 +100,7 @@ <ClCompile Include="httpsys.cpp" /> <ClCompile Include="httpuws.cpp" /> <ClCompile Include="iothreadpool.cpp" /> + <ClCompile Include="zenhttp.cpp" /> </ItemGroup> <ItemGroup> <ClInclude Include="httpnull.h" /> diff --git a/zenhttp/zenhttp.vcxproj.filters b/zenhttp/zenhttp.vcxproj.filters index da292c18f..17f71bed1 100644 --- a/zenhttp/zenhttp.vcxproj.filters +++ b/zenhttp/zenhttp.vcxproj.filters @@ -8,6 +8,7 @@ <ClCompile Include="httpnull.cpp" /> <ClCompile Include="httpuws.cpp" /> <ClCompile Include="httpshared.cpp" /> + <ClCompile Include="zenhttp.cpp" /> </ItemGroup> <ItemGroup> <ClInclude Include="include\zenhttp\httpclient.h" /> |