aboutsummaryrefslogtreecommitdiff
path: root/zenhttp
diff options
context:
space:
mode:
authorPer Larsson <[email protected]>2021-12-09 17:01:57 +0100
committerPer Larsson <[email protected]>2021-12-09 17:01:57 +0100
commit20f3c16b0012cfb8ce7bf9b6dd06a2720b6885c6 (patch)
treefbb0f274840a12c32d93c7e342c0427f2617a651 /zenhttp
parentDisabled cache tracker. (diff)
parentReturn status_code as ErrorCode from jupiter api if not successful (diff)
downloadzen-20f3c16b0012cfb8ce7bf9b6dd06a2720b6885c6.tar.xz
zen-20f3c16b0012cfb8ce7bf9b6dd06a2720b6885c6.zip
Merged main.
Diffstat (limited to 'zenhttp')
-rw-r--r--zenhttp/httpasio.cpp99
-rw-r--r--zenhttp/httpserver.cpp81
-rw-r--r--zenhttp/httpsys.cpp167
-rw-r--r--zenhttp/httpsys.h20
-rw-r--r--zenhttp/include/zenhttp/httpserver.h2
5 files changed, 241 insertions, 128 deletions
diff --git a/zenhttp/httpasio.cpp b/zenhttp/httpasio.cpp
index d5fe9adbb..7ee7193d1 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;
@@ -114,7 +122,7 @@ struct HttpRequest
HttpVerb RequestVerb() const { return m_RequestVerb; }
bool IsKeepAlive() const { return m_KeepAlive; }
- std::string_view Url() const { return std::string_view(m_Url, m_UrlLength); }
+ std::string_view Url() const { return m_NormalizedUrl.empty() ? std::string_view(m_Url, m_UrlLength) : m_NormalizedUrl; }
std::string_view QueryString() const { return std::string_view(m_QueryString, m_QueryLength); }
IoBuffer Body() { return m_BodyBuffer; }
@@ -171,6 +179,7 @@ private:
uint64_t m_BodyPosition = 0;
http_parser m_Parser;
char m_HeaderBuffer[1024];
+ std::string m_NormalizedUrl;
void AppendInputBytes(const char* Data, size_t Bytes);
void AppendCurrentHeader();
@@ -318,6 +327,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 +340,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 +381,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 +402,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 +431,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 +440,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 +495,23 @@ 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))
+ {
+ try
+ {
+ Service->HandleRequest(Request);
+ }
+ catch (std::exception& ex)
+ {
+ ZEN_ERROR("Caught exception while handling request: '{}'", ex.what());
+
+ Request.WriteResponse(HttpResponseCode::InternalServerError, HttpContentType::kText, ex.what());
+ }
+
+ }
if (std::unique_ptr<HttpResponse> Response = std::move(Request.m_Response))
{
@@ -737,6 +761,37 @@ HttpRequest::TerminateConnection()
m_Connection.TerminateConnection();
}
+static void
+NormalizeUrlPath(const char* Url, size_t UrlLength, std::string& NormalizedUrl)
+{
+ bool LastCharWasSeparator = false;
+ for (std::string_view::size_type UrlIndex = 0; UrlIndex < UrlLength; ++UrlIndex)
+ {
+ const char UrlChar = Url[UrlIndex];
+ const bool IsSeparator = (UrlChar == '/');
+
+ if (IsSeparator && LastCharWasSeparator)
+ {
+ if (NormalizedUrl.empty())
+ {
+ NormalizedUrl.reserve(UrlLength);
+ NormalizedUrl.append(Url, UrlIndex);
+ }
+
+ if (!LastCharWasSeparator)
+ {
+ NormalizedUrl.push_back('/');
+ }
+ }
+ else if (!NormalizedUrl.empty())
+ {
+ NormalizedUrl.push_back(UrlChar);
+ }
+
+ LastCharWasSeparator = IsSeparator;
+ }
+}
+
int
HttpRequest::OnHeadersComplete()
{
@@ -803,6 +858,9 @@ HttpRequest::OnHeadersComplete()
m_QueryLength = Url.size() - QuerySplit - 1;
}
+ NormalizeUrlPath(m_Url, m_UrlLength, m_NormalizedUrl);
+
+
return 0;
}
@@ -843,6 +901,7 @@ HttpRequest::ResetState()
m_BodyBuffer = {};
m_BodyPosition = 0;
m_Headers.clear();
+ m_NormalizedUrl.clear();
}
int
@@ -935,7 +994,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 +1158,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 +1172,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 011468715..3326f3d4a 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>
@@ -637,6 +638,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..e9472e3b8 100644
--- a/zenhttp/httpsys.cpp
+++ b/zenhttp/httpsys.cpp
@@ -748,15 +748,20 @@ HttpSysServer::~HttpSysServer()
}
void
-HttpSysServer::Initialize(const wchar_t* UrlPath)
+HttpSysServer::InitializeServer(int BasePort)
{
+ using namespace std::literals;
+
+ WideStringBuilder<64> WildcardUrlPath;
+ WildcardUrlPath << u8"http://*:"sv << int64_t(BasePort) << u8"/"sv;
+
m_IsOk = false;
ULONG Result = HttpCreateServerSession(HTTPAPI_VERSION_2, &m_HttpSessionId, 0);
if (Result != NO_ERROR)
{
- ZEN_ERROR("Failed to create server session for '{}': {:#x}", WideToUtf8(UrlPath), Result);
+ ZEN_ERROR("Failed to create server session for '{}': {:#x}", WideToUtf8(WildcardUrlPath), Result);
return;
}
@@ -765,18 +770,44 @@ HttpSysServer::Initialize(const wchar_t* UrlPath)
if (Result != NO_ERROR)
{
- ZEN_ERROR("Failed to create URL group for '{}': {:#x}", WideToUtf8(UrlPath), Result);
+ ZEN_ERROR("Failed to create URL group for '{}': {:#x}", WideToUtf8(WildcardUrlPath), Result);
return;
}
- m_BaseUri = UrlPath;
+ Result = HttpAddUrlToUrlGroup(m_HttpUrlGroupId, WildcardUrlPath.c_str(), HTTP_URL_CONTEXT(0), 0);
- Result = HttpAddUrlToUrlGroup(m_HttpUrlGroupId, UrlPath, HTTP_URL_CONTEXT(0), 0);
+ m_BaseUris.clear();
+ if (Result == NO_ERROR)
+ {
+ m_BaseUris.push_back(WildcardUrlPath.c_str());
+ }
+ else
+ {
+ // If we can't register the wildcard path, we fall back to local paths
+ // This local paths allow requests originating locally to function, but will not allow
+ // remote origin requests to function. This can be remedied by using netsh
+ // during an install process to grant permissions to route public access to the appropriate
+ // port for the current user. eg:
+ // netsh http add urlacl url=http://*:1337/ user=<some_user>
- if (Result != NO_ERROR)
+ const std::u8string_view Hosts[] = { u8"[::1]"sv, u8"localhost"sv, u8"127.0.0.1"sv };
+
+ for (const std::u8string_view Host : Hosts)
+ {
+ WideStringBuilder<64> LocalUrlPath;
+ LocalUrlPath << u8"http://"sv << Host << u8":"sv << int64_t(BasePort) << u8"/"sv;
+
+ if (HttpAddUrlToUrlGroup(m_HttpUrlGroupId, LocalUrlPath.c_str(), HTTP_URL_CONTEXT(0), 0) == NO_ERROR)
+ {
+ m_BaseUris.push_back(LocalUrlPath.c_str());
+ }
+ }
+ }
+
+ if (m_BaseUris.empty())
{
- ZEN_ERROR("Failed to add base URL to URL group for '{}': {:#x}", WideToUtf8(UrlPath), Result);
+ ZEN_ERROR("Failed to add base URL to URL group for '{}': {:#x}", WideToUtf8(WildcardUrlPath), Result);
return;
}
@@ -791,7 +822,7 @@ HttpSysServer::Initialize(const wchar_t* UrlPath)
if (Result != NO_ERROR)
{
- ZEN_ERROR("Failed to create request queue for '{}': {:#x}", WideToUtf8(UrlPath), Result);
+ ZEN_ERROR("Failed to create request queue for '{}': {:#x}", WideToUtf8(m_BaseUris.front()), Result);
return;
}
@@ -803,7 +834,7 @@ HttpSysServer::Initialize(const wchar_t* UrlPath)
if (Result != NO_ERROR)
{
- ZEN_ERROR("Failed to set server binding property for '{}': {:#x}", WideToUtf8(UrlPath), Result);
+ ZEN_ERROR("Failed to set server binding property for '{}': {:#x}", WideToUtf8(m_BaseUris.front()), Result);
return;
}
@@ -815,13 +846,13 @@ HttpSysServer::Initialize(const wchar_t* UrlPath)
if (ErrorCode)
{
- ZEN_ERROR("Failed to create IOCP for '{}': {}", WideToUtf8(UrlPath), ErrorCode.message());
+ ZEN_ERROR("Failed to create IOCP for '{}': {}", WideToUtf8(m_BaseUris.front()), ErrorCode.message());
}
else
{
m_IsOk = true;
- ZEN_INFO("Started http.sys server at '{}'", WideToUtf8(UrlPath));
+ ZEN_INFO("Started http.sys server at '{}'", WideToUtf8(m_BaseUris.front()));
}
}
@@ -952,15 +983,18 @@ HttpSysServer::RegisterService(const char* UrlPath, HttpService& Service)
// Convert to wide string
- std::wstring Url16 = m_BaseUri + PathUtf16;
+ for (const std::wstring& BaseUri : m_BaseUris)
+ {
+ std::wstring Url16 = BaseUri + PathUtf16;
- ULONG Result = HttpAddUrlToUrlGroup(m_HttpUrlGroupId, Url16.c_str(), HTTP_URL_CONTEXT(&Service), 0 /* Reserved */);
+ ULONG Result = HttpAddUrlToUrlGroup(m_HttpUrlGroupId, Url16.c_str(), HTTP_URL_CONTEXT(&Service), 0 /* Reserved */);
- if (Result != NO_ERROR)
- {
- ZEN_ERROR("HttpAddUrlToUrlGroup failed with result: '{}'", GetSystemErrorAsString(Result));
+ if (Result != NO_ERROR)
+ {
+ ZEN_ERROR("HttpAddUrlToUrlGroup failed with result: '{}'", GetSystemErrorAsString(Result));
- return;
+ return;
+ }
}
}
@@ -978,13 +1012,16 @@ HttpSysServer::UnregisterService(const char* UrlPath, HttpService& Service)
// Convert to wide string
- std::wstring Url16 = m_BaseUri + PathUtf16;
+ for (const std::wstring& BaseUri : m_BaseUris)
+ {
+ std::wstring Url16 = BaseUri + PathUtf16;
- ULONG Result = HttpRemoveUrlFromUrlGroup(m_HttpUrlGroupId, Url16.c_str(), 0);
+ ULONG Result = HttpRemoveUrlFromUrlGroup(m_HttpUrlGroupId, Url16.c_str(), 0);
- if (Result != NO_ERROR)
- {
- ZEN_ERROR("HttpRemoveUrlFromUrlGroup failed with result: '{}'", GetSystemErrorAsString(Result));
+ if (Result != NO_ERROR)
+ {
+ ZEN_ERROR("HttpRemoveUrlFromUrlGroup failed with result: '{}'", GetSystemErrorAsString(Result));
+ }
}
}
@@ -1131,83 +1168,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;
}
@@ -1641,12 +1607,7 @@ InitialRequestHandler::HandleCompletion(ULONG IoResult, ULONG_PTR NumberOfBytesT
void
HttpSysServer::Initialize(int BasePort)
{
- using namespace std::literals;
-
- WideStringBuilder<64> BaseUri;
- BaseUri << u8"http://*:"sv << int64_t(BasePort) << u8"/"sv;
-
- Initialize(BaseUri.c_str());
+ InitializeServer(BasePort);
StartServer();
}
diff --git a/zenhttp/httpsys.h b/zenhttp/httpsys.h
index 46ba122cc..7df8fba8f 100644
--- a/zenhttp/httpsys.h
+++ b/zenhttp/httpsys.h
@@ -52,7 +52,7 @@ public:
inline bool IsAsyncResponseEnabled() const { return m_IsAsyncResponseEnabled; }
private:
- void Initialize(const wchar_t* UrlPath);
+ void InitializeServer(int BasePort);
void Cleanup();
void StartServer();
@@ -75,15 +75,15 @@ private:
WinIoThreadPool m_ThreadPool;
WorkerThreadPool m_AsyncWorkPool;
- std::wstring m_BaseUri; // http://*:nnnn/
- HTTP_SERVER_SESSION_ID m_HttpSessionId = 0;
- HTTP_URL_GROUP_ID m_HttpUrlGroupId = 0;
- HANDLE m_RequestQueueHandle = 0;
- std::atomic_int32_t m_PendingRequests{0};
- std::atomic<int32_t> m_IsShuttingDown{0};
- int32_t m_MinPendingRequests = 16;
- int32_t m_MaxPendingRequests = 128;
- Event m_ShutdownEvent;
+ std::vector<std::wstring> m_BaseUris; // eg: http://*:nnnn/
+ HTTP_SERVER_SESSION_ID m_HttpSessionId = 0;
+ HTTP_URL_GROUP_ID m_HttpUrlGroupId = 0;
+ HANDLE m_RequestQueueHandle = 0;
+ std::atomic_int32_t m_PendingRequests{0};
+ std::atomic_int32_t m_IsShuttingDown{0};
+ int32_t m_MinPendingRequests = 16;
+ int32_t m_MaxPendingRequests = 128;
+ Event m_ShutdownEvent;
};
} // namespace zen
diff --git a/zenhttp/include/zenhttp/httpserver.h b/zenhttp/include/zenhttp/httpserver.h
index 19b4c63d6..b32359d67 100644
--- a/zenhttp/include/zenhttp/httpserver.h
+++ b/zenhttp/include/zenhttp/httpserver.h
@@ -303,6 +303,8 @@ private:
std::map<std::string, RpcFunction> m_Functions;
};
+bool HandlePackageOffers(HttpService& Service, HttpServerRequest& Request, Ref<IHttpPackageHandler>& PackageHandlerRef);
+
void http_forcelink(); // internal
} // namespace zen