diff options
| author | Stefan Boberg <[email protected]> | 2023-10-13 14:46:49 +0200 |
|---|---|---|
| committer | GitHub <[email protected]> | 2023-10-13 14:46:49 +0200 |
| commit | c3fad0e98576ff5dee3ee63725459d46e201fa34 (patch) | |
| tree | 91455786fac76ffb6a83ff24620329780ce08545 /src/zenhttp/servers/httpplugin.cpp | |
| parent | improved http.sys initialization diagnostics and amended logic for dedicated ... (diff) | |
| download | zen-c3fad0e98576ff5dee3ee63725459d46e201fa34.tar.xz zen-c3fad0e98576ff5dee3ee63725459d46e201fa34.zip | |
support for multiple http servers (#473)
* added support for having multiple http servers active in one session
* added configuration API to pluggable transports
* removed pimpl pattern from some pluggable transports implementations
Diffstat (limited to 'src/zenhttp/servers/httpplugin.cpp')
| -rw-r--r-- | src/zenhttp/servers/httpplugin.cpp | 233 |
1 files changed, 104 insertions, 129 deletions
diff --git a/src/zenhttp/servers/httpplugin.cpp b/src/zenhttp/servers/httpplugin.cpp index 2e934473e..3c727763b 100644 --- a/src/zenhttp/servers/httpplugin.cpp +++ b/src/zenhttp/servers/httpplugin.cpp @@ -8,8 +8,8 @@ # include <zencore/except.h> # include <zencore/logging.h> +# include <zencore/thread.h> # include <zencore/trace.h> -# include <zencore/workthreadpool.h> # include <zenhttp/httpserver.h> # include <memory> @@ -74,18 +74,22 @@ private: ////////////////////////////////////////////////////////////////////////// -struct HttpPluginServerImpl : public TransportServer +struct HttpPluginServerImpl : public HttpPluginServer, TransportServer { HttpPluginServerImpl(); ~HttpPluginServerImpl(); - void AddPlugin(Ref<TransportPlugin> Plugin); - void RemovePlugin(Ref<TransportPlugin> Plugin); + // HttpPluginServer - void Start(); - void Stop(); + virtual void RegisterService(HttpService& Service) override; + virtual int Initialize(int BasePort) override; + virtual void Run(bool IsInteractiveSession) override; + virtual void RequestExit() override; + virtual void Close() override; + + virtual void AddPlugin(Ref<TransportPlugin> Plugin) override; + virtual void RemovePlugin(Ref<TransportPlugin> Plugin) override; - void RegisterService(const char* InUrlPath, HttpService& Service); HttpService* RouteRequest(std::string_view Url); struct ServiceEntry @@ -94,9 +98,11 @@ struct HttpPluginServerImpl : public TransportServer HttpService* Service; }; + bool m_IsInitialized = false; RwLock m_Lock; std::vector<ServiceEntry> m_UriHandlers; std::vector<Ref<TransportPlugin>> m_Plugins; + Event m_ShutdownEvent; // TransportServer @@ -568,149 +574,71 @@ HttpPluginServerImpl::CreateConnectionHandler(TransportConnection* Connection) return Handler; } -void -HttpPluginServerImpl::Start() +int +HttpPluginServerImpl::Initialize(int BasePort) { - RwLock::ExclusiveLockScope _(m_Lock); - - for (auto& Plugin : m_Plugins) + try { - try - { - Plugin->Initialize(this); - } - catch (std::exception& Ex) + RwLock::ExclusiveLockScope _(m_Lock); + + for (auto& Plugin : m_Plugins) { - ZEN_WARN("exception caught during plugin initialization: {}", Ex.what()); + try + { + Plugin->Initialize(this); + } + catch (std::exception& Ex) + { + ZEN_WARN("exception caught during plugin initialization: {}", Ex.what()); + } } } -} - -void -HttpPluginServerImpl::Stop() -{ - RwLock::ExclusiveLockScope _(m_Lock); - - for (auto& Plugin : m_Plugins) + catch (std::exception& ex) { - try - { - Plugin->Shutdown(); - } - catch (std::exception& Ex) - { - ZEN_WARN("exception caught during plugin shutdown: {}", Ex.what()); - } - - Plugin = nullptr; + ZEN_WARN("Caught exception starting http plugin server: {}", ex.what()); } - m_Plugins.clear(); -} + m_IsInitialized = true; -void -HttpPluginServerImpl::AddPlugin(Ref<TransportPlugin> Plugin) -{ - RwLock::ExclusiveLockScope _(m_Lock); - m_Plugins.emplace_back(std::move(Plugin)); + return BasePort; } void -HttpPluginServerImpl::RemovePlugin(Ref<TransportPlugin> Plugin) +HttpPluginServerImpl::Close() { - RwLock::ExclusiveLockScope _(m_Lock); - auto It = std::find(begin(m_Plugins), end(m_Plugins), Plugin); - if (It != m_Plugins.end()) - { - m_Plugins.erase(It); - } -} + if (!m_IsInitialized) + return; -void -HttpPluginServerImpl::RegisterService(const char* InUrlPath, HttpService& Service) -{ - std::string_view UrlPath(InUrlPath); - Service.SetUriPrefixLength(UrlPath.size()); - if (!UrlPath.empty() && UrlPath.back() == '/') + try { - UrlPath.remove_suffix(1); - } - - RwLock::ExclusiveLockScope _(m_Lock); - m_UriHandlers.push_back({std::string(UrlPath), &Service}); -} - -HttpService* -HttpPluginServerImpl::RouteRequest(std::string_view Url) -{ - RwLock::SharedLockScope _(m_Lock); + RwLock::ExclusiveLockScope _(m_Lock); - HttpService* CandidateService = nullptr; - std::string::size_type CandidateMatchSize = 0; - for (const ServiceEntry& SvcEntry : m_UriHandlers) - { - const std::string& SvcUrl = SvcEntry.ServiceUrlPath; - const std::string::size_type SvcUrlSize = SvcUrl.size(); - if ((SvcUrlSize >= CandidateMatchSize) && Url.compare(0, SvcUrlSize, SvcUrl) == 0 && - ((SvcUrlSize == Url.size()) || (Url[SvcUrlSize] == '/'))) + for (auto& Plugin : m_Plugins) { - CandidateMatchSize = SvcUrl.size(); - CandidateService = SvcEntry.Service; - } - } - - return CandidateService; -} - -////////////////////////////////////////////////////////////////////////// - -HttpPluginServer::HttpPluginServer(unsigned int ThreadCount) -: m_ThreadCount(ThreadCount != 0 ? ThreadCount : Max(std::thread::hardware_concurrency(), 8u)) -, m_Impl(new HttpPluginServerImpl) -{ -} - -HttpPluginServer::~HttpPluginServer() -{ - if (m_Impl) - { - ZEN_ERROR("~HttpPluginServer() called without calling Close() first"); - } -} - -int -HttpPluginServer::Initialize(int BasePort) -{ - try - { - m_Impl->Start(); - } - catch (std::exception& ex) - { - ZEN_WARN("Caught exception starting http plugin server: {}", ex.what()); - } + try + { + Plugin->Shutdown(); + } + catch (std::exception& Ex) + { + ZEN_WARN("exception caught during plugin shutdown: {}", Ex.what()); + } - return BasePort; -} + Plugin = nullptr; + } -void -HttpPluginServer::Close() -{ - try - { - m_Impl->Stop(); + m_Plugins.clear(); } catch (std::exception& ex) { ZEN_WARN("Caught exception stopping http plugin server: {}", ex.what()); } - delete m_Impl; - m_Impl = nullptr; + m_IsInitialized = false; } void -HttpPluginServer::Run(bool IsInteractive) +HttpPluginServerImpl::Run(bool IsInteractive) { const bool TestMode = !IsInteractive; @@ -754,27 +682,74 @@ HttpPluginServer::Run(bool IsInteractive) } void -HttpPluginServer::RequestExit() +HttpPluginServerImpl::RequestExit() { m_ShutdownEvent.Set(); } void -HttpPluginServer::RegisterService(HttpService& Service) +HttpPluginServerImpl::AddPlugin(Ref<TransportPlugin> Plugin) { - m_Impl->RegisterService(Service.BaseUri(), Service); + RwLock::ExclusiveLockScope _(m_Lock); + m_Plugins.emplace_back(std::move(Plugin)); } void -HttpPluginServer::AddPlugin(Ref<TransportPlugin> Plugin) +HttpPluginServerImpl::RemovePlugin(Ref<TransportPlugin> Plugin) { - m_Impl->AddPlugin(Plugin); + RwLock::ExclusiveLockScope _(m_Lock); + auto It = std::find(begin(m_Plugins), end(m_Plugins), Plugin); + if (It != m_Plugins.end()) + { + m_Plugins.erase(It); + } } void -HttpPluginServer::RemovePlugin(Ref<TransportPlugin> Plugin) +HttpPluginServerImpl::RegisterService(HttpService& Service) +{ + std::string_view UrlPath(Service.BaseUri()); + 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}); +} + +HttpService* +HttpPluginServerImpl::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; + const std::string::size_type SvcUrlSize = SvcUrl.size(); + if ((SvcUrlSize >= CandidateMatchSize) && Url.compare(0, SvcUrlSize, SvcUrl) == 0 && + ((SvcUrlSize == Url.size()) || (Url[SvcUrlSize] == '/'))) + { + CandidateMatchSize = SvcUrl.size(); + CandidateService = SvcEntry.Service; + } + } + + return CandidateService; +} + +////////////////////////////////////////////////////////////////////////// + +struct HttpPluginServerImpl; + +Ref<HttpPluginServer> +CreateHttpPluginServer() { - m_Impl->RemovePlugin(Plugin); + return Ref<HttpPluginServer>(new HttpPluginServerImpl); } } // namespace zen |