aboutsummaryrefslogtreecommitdiff
path: root/zenhttp
diff options
context:
space:
mode:
authorMartin Ridgers <[email protected]>2021-09-16 10:13:28 +0200
committerMartin Ridgers <[email protected]>2021-09-16 10:13:58 +0200
commit7aa3ceabe4254479bd066ae3ea941396fdc6733c (patch)
treea7d0a7fde0a5a3c42302238965c25c665fc28005 /zenhttp
parentMissing include (diff)
parentAdded some placeholder HttpClient functions to be fleshed out (diff)
downloadzen-7aa3ceabe4254479bd066ae3ea941396fdc6733c.tar.xz
zen-7aa3ceabe4254479bd066ae3ea941396fdc6733c.zip
Merge from main
Diffstat (limited to 'zenhttp')
-rw-r--r--zenhttp/httpclient.cpp25
-rw-r--r--zenhttp/httpserver.cpp106
-rw-r--r--zenhttp/httpsys.cpp30
-rw-r--r--zenhttp/include/zenhttp/httpclient.h10
-rw-r--r--zenhttp/include/zenhttp/httpcommon.h4
-rw-r--r--zenhttp/include/zenhttp/httpserver.h4
-rw-r--r--zenhttp/include/zenhttp/zenhttp.h6
-rw-r--r--zenhttp/zenhttp.cpp13
-rw-r--r--zenhttp/zenhttp.vcxproj1
-rw-r--r--zenhttp/zenhttp.vcxproj.filters1
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" />