1#pragma once
2
3#include <Poco/Net/HTTPRequestHandlerFactory.h>
4#include <Poco/Net/HTTPServerRequest.h>
5#include <Poco/Net/HTTPServerResponse.h>
6#include <common/logger_useful.h>
7#include "IServer.h"
8#include "HTTPHandler.h"
9#include "InterserverIOHTTPHandler.h"
10#include "NotFoundHandler.h"
11#include "PingRequestHandler.h"
12#include "PrometheusRequestHandler.h"
13#include "ReplicasStatusHandler.h"
14#include "RootRequestHandler.h"
15
16
17namespace DB
18{
19
20/// Handle request using child handlers
21class HTTPRequestHandlerFactoryMain : public Poco::Net::HTTPRequestHandlerFactory
22{
23private:
24 using TThis = HTTPRequestHandlerFactoryMain;
25
26 IServer & server;
27 Logger * log;
28 std::string name;
29
30 std::vector<std::unique_ptr<Poco::Net::HTTPRequestHandlerFactory>> child_handler_factories;
31
32public:
33 HTTPRequestHandlerFactoryMain(IServer & server_, const std::string & name_);
34
35 Poco::Net::HTTPRequestHandler * createRequestHandler(const Poco::Net::HTTPServerRequest & request) override;
36
37 template <typename T, typename... TArgs>
38 TThis * addHandler(TArgs &&... args)
39 {
40 child_handler_factories.emplace_back(std::make_unique<T>(server, std::forward<TArgs>(args)...));
41 return this;
42 }
43};
44
45
46/// Handle POST or GET with params
47template <typename HandleType>
48class HTTPQueryRequestHandlerFactory : public Poco::Net::HTTPRequestHandlerFactory
49{
50private:
51 IServer & server;
52
53public:
54 HTTPQueryRequestHandlerFactory(IServer & server_) : server(server_) {}
55
56 Poco::Net::HTTPRequestHandler * createRequestHandler(const Poco::Net::HTTPServerRequest & request) override
57 {
58 if (request.getURI().find('?') != std::string::npos || request.getMethod() == Poco::Net::HTTPRequest::HTTP_POST)
59 return new HandleType(server);
60 return nullptr;
61 }
62};
63
64
65/// Handle GET or HEAD endpoint on specified path
66template <typename TGetEndpoint>
67class HTTPGetRequestHandlerFactory : public Poco::Net::HTTPRequestHandlerFactory
68{
69private:
70 IServer & server;
71public:
72 HTTPGetRequestHandlerFactory(IServer & server_) : server(server_) {}
73
74 Poco::Net::HTTPRequestHandler * createRequestHandler(const Poco::Net::HTTPServerRequest & request) override
75 {
76 auto & method = request.getMethod();
77 if (!(method == Poco::Net::HTTPRequest::HTTP_GET || method == Poco::Net::HTTPRequest::HTTP_HEAD))
78 return nullptr;
79
80 auto & uri = request.getURI();
81 bool uri_match = TGetEndpoint::strict_path ? uri == TGetEndpoint::path : startsWith(uri, TGetEndpoint::path);
82 if (uri_match)
83 return new typename TGetEndpoint::HandleType(server);
84
85 return nullptr;
86 }
87};
88
89
90struct RootEndpoint
91{
92 static constexpr auto path = "/";
93 static constexpr auto strict_path = true;
94 using HandleType = RootRequestHandler;
95};
96
97struct PingEndpoint
98{
99 static constexpr auto path = "/ping";
100 static constexpr auto strict_path = true;
101 using HandleType = PingRequestHandler;
102};
103
104struct ReplicasStatusEndpoint
105{
106 static constexpr auto path = "/replicas_status";
107 static constexpr auto strict_path = false;
108 using HandleType = ReplicasStatusHandler;
109};
110
111using HTTPRootRequestHandlerFactory = HTTPGetRequestHandlerFactory<RootEndpoint>;
112using HTTPPingRequestHandlerFactory = HTTPGetRequestHandlerFactory<PingEndpoint>;
113using HTTPReplicasStatusRequestHandlerFactory = HTTPGetRequestHandlerFactory<ReplicasStatusEndpoint>;
114
115template <typename HandleType>
116HTTPRequestHandlerFactoryMain * createDefaultHandlerFatory(IServer & server, const std::string & name)
117{
118 auto handlerFactory = new HTTPRequestHandlerFactoryMain(server, name);
119 handlerFactory->addHandler<HTTPRootRequestHandlerFactory>()
120 ->addHandler<HTTPPingRequestHandlerFactory>()
121 ->addHandler<HTTPReplicasStatusRequestHandlerFactory>()
122 ->addHandler<HTTPQueryRequestHandlerFactory<HandleType>>();
123 return handlerFactory;
124}
125
126
127}
128