aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/clickhouse/src/Server/HTTPHandlerFactory.h
blob: fe11833dc311cc5f7da179c42898b98ef0a2c947 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
#pragma once

#include <Common/AsynchronousMetrics.h>
#include <Server/HTTP/HTMLForm.h>
#include <Server/HTTP/HTTPRequestHandlerFactory.h>
#include <Server/HTTPHandlerRequestFilter.h>
#include <Server/HTTPRequestHandlerFactoryMain.h>
#include <Common/StringUtils/StringUtils.h>

#include <Poco/Util/AbstractConfiguration.h>

namespace DB
{

namespace ErrorCodes
{
    extern const int UNKNOWN_ELEMENT_IN_CONFIG;
}

class IServer;

template <typename TEndpoint>
class HandlingRuleHTTPHandlerFactory : public HTTPRequestHandlerFactory
{
public:
    using Filter = std::function<bool(const HTTPServerRequest &)>;

    template <typename... TArgs>
    explicit HandlingRuleHTTPHandlerFactory(TArgs &&... args)
    {
        creator = [my_args = std::tuple<TArgs...>(std::forward<TArgs>(args) ...)]()
        {
            return std::apply([&](auto && ... endpoint_args)
            {
                return std::make_unique<TEndpoint>(std::forward<decltype(endpoint_args)>(endpoint_args)...);
            }, std::move(my_args));
        };
    }

    void addFilter(Filter cur_filter)
    {
        Filter prev_filter = filter;
        filter = [prev_filter, cur_filter](const auto & request)
        {
            return prev_filter ? prev_filter(request) && cur_filter(request) : cur_filter(request);
        };
    }

    void addFiltersFromConfig(const Poco::Util::AbstractConfiguration & config, const std::string & prefix)
    {
        Poco::Util::AbstractConfiguration::Keys filters_type;
        config.keys(prefix, filters_type);

        for (const auto & filter_type : filters_type)
        {
            if (filter_type == "handler")
                continue;
            else if (filter_type == "url")
                addFilter(urlFilter(config, prefix + ".url"));
            else if (filter_type == "headers")
                addFilter(headersFilter(config, prefix + ".headers"));
            else if (filter_type == "methods")
                addFilter(methodsFilter(config, prefix + ".methods"));
            else
                throw Exception(ErrorCodes::UNKNOWN_ELEMENT_IN_CONFIG, "Unknown element in config: {}.{}", prefix, filter_type);
        }
    }

    void attachStrictPath(const String & strict_path)
    {
        addFilter([strict_path](const auto & request) { return request.getURI() == strict_path; });
    }

    void attachNonStrictPath(const String & non_strict_path)
    {
        addFilter([non_strict_path](const auto & request) { return startsWith(request.getURI(), non_strict_path); });
    }

    /// Handle GET or HEAD endpoint on specified path
    void allowGetAndHeadRequest()
    {
        addFilter([](const auto & request)
        {
            return request.getMethod() == Poco::Net::HTTPRequest::HTTP_GET
                || request.getMethod() == Poco::Net::HTTPRequest::HTTP_HEAD;
        });
    }

    /// Handle Post request or (Get or Head) with params or OPTIONS requests
    void allowPostAndGetParamsAndOptionsRequest()
    {
        addFilter([](const auto & request)
        {
            return (request.getURI().find('?') != std::string::npos
                && (request.getMethod() == Poco::Net::HTTPRequest::HTTP_GET
                || request.getMethod() == Poco::Net::HTTPRequest::HTTP_HEAD))
                || request.getMethod() == Poco::Net::HTTPRequest::HTTP_OPTIONS
                || request.getMethod() == Poco::Net::HTTPRequest::HTTP_POST;
        });
    }

    std::unique_ptr<HTTPRequestHandler> createRequestHandler(const HTTPServerRequest & request) override
    {
        return filter(request) ? creator() : nullptr;
    }

private:
    Filter filter;
    std::function<std::unique_ptr<HTTPRequestHandler> ()> creator;
};

HTTPRequestHandlerFactoryPtr createStaticHandlerFactory(IServer & server,
    const Poco::Util::AbstractConfiguration & config,
    const std::string & config_prefix);

HTTPRequestHandlerFactoryPtr createDynamicHandlerFactory(IServer & server,
    const Poco::Util::AbstractConfiguration & config,
    const std::string & config_prefix);

HTTPRequestHandlerFactoryPtr createPredefinedHandlerFactory(IServer & server,
    const Poco::Util::AbstractConfiguration & config,
    const std::string & config_prefix);

HTTPRequestHandlerFactoryPtr createReplicasStatusHandlerFactory(IServer & server,
    const Poco::Util::AbstractConfiguration & config,
    const std::string & config_prefix);

HTTPRequestHandlerFactoryPtr
createPrometheusHandlerFactory(IServer & server,
    const Poco::Util::AbstractConfiguration & config,
    AsynchronousMetrics & async_metrics,
    const std::string & config_prefix);

HTTPRequestHandlerFactoryPtr
createPrometheusMainHandlerFactory(IServer & server,
    const Poco::Util::AbstractConfiguration & config,
    AsynchronousMetrics & async_metrics,
    const std::string & name);

/// @param server - used in handlers to check IServer::isCancelled()
/// @param config - not the same as server.config(), since it can be newer
/// @param async_metrics - used for prometheus (in case of prometheus.asynchronous_metrics=true)
HTTPRequestHandlerFactoryPtr createHandlerFactory(IServer & server,
    const Poco::Util::AbstractConfiguration & config,
    AsynchronousMetrics & async_metrics,
    const std::string & name);

}