HTTPHandlerRequestFilter.h 3.6 KB
Newer Older
Z
zhang2014 已提交
1 2
#pragma once

3 4 5 6 7
#include <Server/HTTP/HTTPServerRequest.h>
#include <Common/Exception.h>
#include <Common/StringUtils/StringUtils.h>
#include <common/StringRef.h>
#include <common/find_symbols.h>
Z
zhang2014 已提交
8 9 10 11

#include <re2/re2.h>
#include <re2/stringpiece.h>
#include <Poco/StringTokenizer.h>
12
#include <Poco/Util/LayeredConfiguration.h>
Z
zhang2014 已提交
13

14
#include <unordered_map>
Z
zhang2014 已提交
15 16 17 18 19 20 21 22 23

namespace DB
{

namespace ErrorCodes
{
    extern const int CANNOT_COMPILE_REGEXP;
}

24
using CompiledRegexPtr = std::shared_ptr<const re2::RE2>;
25

A
fix  
Alexander Tokmakov 已提交
26 27
static inline bool checkRegexExpression(const StringRef & match_str, const CompiledRegexPtr & compiled_regex)
{
28 29
    int num_captures = compiled_regex->NumberOfCapturingGroups() + 1;

A
fix  
Alexander Tokmakov 已提交
30 31 32
    re2::StringPiece matches[num_captures];
    re2::StringPiece match_input(match_str.data, match_str.size);
    return compiled_regex->Match(match_input, 0, match_str.size, re2::RE2::Anchor::ANCHOR_BOTH, matches, num_captures);
Z
zhang2014 已提交
33 34
}

A
fix  
Alexander Tokmakov 已提交
35
static inline bool checkExpression(const StringRef & match_str, const std::pair<String, CompiledRegexPtr> & expression)
Z
zhang2014 已提交
36
{
A
fix  
Alexander Tokmakov 已提交
37 38
    if (expression.second)
        return checkRegexExpression(match_str, expression.second);
39

A
fix  
Alexander Tokmakov 已提交
40
    return match_str == expression.first;
Z
zhang2014 已提交
41 42
}

43
static inline auto methodsFilter(Poco::Util::AbstractConfiguration & config, const std::string & config_path)
Z
zhang2014 已提交
44
{
45 46
    std::vector<String> methods;
    Poco::StringTokenizer tokenizer(config.getString(config_path), ",");
Z
zhang2014 已提交
47

48 49
    for (const auto & iterator : tokenizer)
        methods.emplace_back(Poco::toUpper(Poco::trim(iterator)));
50

51
    return [methods](const HTTPServerRequest & request) { return std::count(methods.begin(), methods.end(), request.getMethod()); };
52
}
Z
zhang2014 已提交
53

A
fix  
Alexander Tokmakov 已提交
54 55 56 57 58 59 60 61 62 63 64 65 66
static inline auto getExpression(const std::string & expression)
{
    if (!startsWith(expression, "regex:"))
        return std::make_pair(expression, CompiledRegexPtr{});

    auto compiled_regex = std::make_shared<const re2::RE2>(expression.substr(6));

    if (!compiled_regex->ok())
        throw Exception("cannot compile re2: " + expression + " for http handling rule, error: " + compiled_regex->error() +
                        ". Look at https://github.com/google/re2/wiki/Syntax for reference.", ErrorCodes::CANNOT_COMPILE_REGEXP);
    return std::make_pair(expression, compiled_regex);
}

67 68
static inline auto urlFilter(Poco::Util::AbstractConfiguration & config, const std::string & config_path)
{
69
    return [expression = getExpression(config.getString(config_path))](const HTTPServerRequest & request)
Z
zhang2014 已提交
70
    {
71 72
        const auto & uri = request.getURI();
        const auto & end = find_first_symbols<'?'>(uri.data(), uri.data() + uri.size());
Z
zhang2014 已提交
73

74 75
        return checkExpression(StringRef(uri.data(), end - uri.data()), expression);
    };
Z
zhang2014 已提交
76 77
}

78
static inline auto headersFilter(Poco::Util::AbstractConfiguration & config, const std::string & prefix)
Z
zhang2014 已提交
79
{
A
fix  
Alexander Tokmakov 已提交
80
    std::unordered_map<String, std::pair<String, CompiledRegexPtr>> headers_expression;
81 82
    Poco::Util::AbstractConfiguration::Keys headers_name;
    config.keys(prefix, headers_name);
Z
zhang2014 已提交
83

84 85
    for (const auto & header_name : headers_name)
    {
A
fix  
Alexander Tokmakov 已提交
86
        const auto & expression = getExpression(config.getString(prefix + "." + header_name));
87 88 89 90
        checkExpression("", expression);    /// Check expression syntax is correct
        headers_expression.emplace(std::make_pair(header_name, expression));
    }

91
    return [headers_expression](const HTTPServerRequest & request)
92 93 94
    {
        for (const auto & [header_name, header_expression] : headers_expression)
        {
Z
zhang2014 已提交
95
            const auto & header_value = request.get(header_name, "");
96 97 98 99 100 101
            if (!checkExpression(StringRef(header_value.data(), header_value.size()), header_expression))
                return false;
        }

        return true;
    };
Z
zhang2014 已提交
102 103 104
}

}