1
#pragma once
2

            
3
#include "envoy/http/filter.h"
4
#include "envoy/matcher/matcher.h"
5
#include "envoy/server/factory_context.h"
6
#include "envoy/type/matcher/v3/http_inputs.pb.h"
7
#include "envoy/type/matcher/v3/http_inputs.pb.validate.h"
8

            
9
#include "source/common/http/header_utility.h"
10
#include "source/common/http/utility.h"
11

            
12
namespace Envoy {
13
namespace Http {
14
namespace Matching {
15
/**
16
 * Common base class for all the header/trailer DataInputs.
17
 */
18
template <class HeaderType>
19
class HttpHeadersDataInputBase : public Matcher::DataInput<HttpMatchingData> {
20
public:
21
1030
  explicit HttpHeadersDataInputBase(const std::string& name) : name_(name) {}
22

            
23
  virtual OptRef<const HeaderType> headerMap(const HttpMatchingData& data) const PURE;
24

            
25
1394
  Matcher::DataInputGetResult get(const HttpMatchingData& data) const override {
26
1394
    const OptRef<const HeaderType> maybe_headers = headerMap(data);
27

            
28
1394
    if (!maybe_headers) {
29
16
      return Matcher::DataInputGetResult::NoData(Matcher::DataAvailability::NotAvailable);
30
16
    }
31

            
32
1378
    auto header_string = HeaderUtility::getAllOfHeaderAsString(*maybe_headers, name_, ",");
33

            
34
1378
    if (header_string.result()) {
35
1322
      return Matcher::DataInputGetResult::CreateString(std::string(header_string.result().value()));
36
1322
    }
37

            
38
56
    return Matcher::DataInputGetResult::NoData();
39
1378
  }
40

            
41
private:
42
  const LowerCaseString name_;
43
};
44

            
45
/**
46
 * Common base class for all the header/trailer DataInputsFactory.
47
 */
48
template <class DataInputType, class ProtoType>
49
class HttpHeadersDataInputFactoryBase : public Matcher::DataInputFactory<HttpMatchingData> {
50
public:
51
5260
  explicit HttpHeadersDataInputFactoryBase(const std::string& name) : name_(name) {}
52

            
53
47948
  std::string name() const override { return "envoy.matching.inputs." + name_; }
54

            
55
  Matcher::DataInputFactoryCb<HttpMatchingData>
56
  createDataInputFactoryCb(const Protobuf::Message& config,
57
1019
                           ProtobufMessage::ValidationVisitor& validation_visitor) override {
58
1019
    const auto& typed_config =
59
1019
        MessageUtil::downcastAndValidate<const ProtoType&>(config, validation_visitor);
60

            
61
1019
    return [header_name = typed_config.header_name()] {
62
1018
      return std::make_unique<DataInputType>(header_name);
63
1018
    };
64
1019
  };
65
2987
  ProtobufTypes::MessagePtr createEmptyConfigProto() override {
66
2987
    return std::make_unique<ProtoType>();
67
2987
  }
68

            
69
private:
70
  const std::string name_;
71
};
72

            
73
class HttpRequestHeadersDataInput : public HttpHeadersDataInputBase<RequestHeaderMap> {
74
public:
75
1008
  explicit HttpRequestHeadersDataInput(const std::string& name) : HttpHeadersDataInputBase(name) {}
76

            
77
1360
  OptRef<const RequestHeaderMap> headerMap(const HttpMatchingData& data) const override {
78
1360
    return data.requestHeaders();
79
1360
  }
80
};
81

            
82
class HttpRequestHeadersDataInputFactory
83
    : public HttpHeadersDataInputFactoryBase<
84
          HttpRequestHeadersDataInput, envoy::type::matcher::v3::HttpRequestHeaderMatchInput> {
85
public:
86
1315
  HttpRequestHeadersDataInputFactory() : HttpHeadersDataInputFactoryBase("request_headers") {}
87
};
88

            
89
DECLARE_FACTORY(HttpRequestHeadersDataInputFactory);
90

            
91
class HttpResponseHeadersDataInput : public HttpHeadersDataInputBase<ResponseHeaderMap> {
92
public:
93
16
  explicit HttpResponseHeadersDataInput(const std::string& name) : HttpHeadersDataInputBase(name) {}
94

            
95
23
  OptRef<const ResponseHeaderMap> headerMap(const HttpMatchingData& data) const override {
96
23
    return data.responseHeaders();
97
23
  }
98
};
99

            
100
class HttpResponseHeadersDataInputFactory
101
    : public HttpHeadersDataInputFactoryBase<
102
          HttpResponseHeadersDataInput, envoy::type::matcher::v3::HttpResponseHeaderMatchInput> {
103
public:
104
1315
  HttpResponseHeadersDataInputFactory() : HttpHeadersDataInputFactoryBase("response_headers") {}
105
};
106

            
107
DECLARE_FACTORY(HttpResponseHeadersDataInputFactory);
108

            
109
class HttpRequestTrailersDataInput : public HttpHeadersDataInputBase<RequestTrailerMap> {
110
public:
111
2
  explicit HttpRequestTrailersDataInput(const std::string& name) : HttpHeadersDataInputBase(name) {}
112

            
113
4
  OptRef<const RequestTrailerMap> headerMap(const HttpMatchingData& data) const override {
114
4
    return data.requestTrailers();
115
4
  }
116
};
117

            
118
class HttpRequestTrailersDataInputFactory
119
    : public HttpHeadersDataInputFactoryBase<
120
          HttpRequestTrailersDataInput, envoy::type::matcher::v3::HttpRequestTrailerMatchInput> {
121
public:
122
1315
  HttpRequestTrailersDataInputFactory() : HttpHeadersDataInputFactoryBase("request_trailers") {}
123
};
124

            
125
DECLARE_FACTORY(HttpRequestTrailersDataInputFactory);
126

            
127
class HttpResponseTrailersDataInput : public HttpHeadersDataInputBase<ResponseTrailerMap> {
128
public:
129
  explicit HttpResponseTrailersDataInput(const std::string& name)
130
4
      : HttpHeadersDataInputBase(name) {}
131

            
132
7
  OptRef<const ResponseTrailerMap> headerMap(const HttpMatchingData& data) const override {
133
7
    return data.responseTrailers();
134
7
  }
135
};
136

            
137
class HttpResponseTrailersDataInputFactory
138
    : public HttpHeadersDataInputFactoryBase<
139
          HttpResponseTrailersDataInput, envoy::type::matcher::v3::HttpResponseTrailerMatchInput> {
140
public:
141
1315
  HttpResponseTrailersDataInputFactory() : HttpHeadersDataInputFactoryBase("response_trailers") {}
142
};
143

            
144
DECLARE_FACTORY(HttpResponseTrailersDataInputFactory);
145

            
146
class HttpRequestQueryParamsDataInput : public Matcher::DataInput<HttpMatchingData> {
147
public:
148
  explicit HttpRequestQueryParamsDataInput(const std::string& query_param)
149
8
      : query_param_(query_param) {}
150

            
151
6
  Matcher::DataInputGetResult get(const HttpMatchingData& data) const override {
152
6
    const auto maybe_headers = data.requestHeaders();
153

            
154
6
    if (!maybe_headers) {
155
1
      return Matcher::DataInputGetResult::NoData(Matcher::DataAvailability::NotAvailable);
156
1
    }
157

            
158
5
    const auto ret = maybe_headers->Path();
159
5
    if (!ret) {
160
1
      return Matcher::DataInputGetResult::NoData(Matcher::DataAvailability::NotAvailable);
161
1
    }
162

            
163
4
    auto params =
164
4
        Http::Utility::QueryParamsMulti::parseAndDecodeQueryString(ret->value().getStringView());
165

            
166
4
    auto ItParam = params.getFirstValue(query_param_);
167
4
    if (!ItParam.has_value()) {
168
1
      return Matcher::DataInputGetResult::NoData();
169
1
    }
170
3
    return Matcher::DataInputGetResult::CreateString(std::move(ItParam.value()));
171
4
  }
172

            
173
private:
174
  const std::string query_param_;
175
};
176

            
177
class HttpRequestQueryParamsDataInputFactory : public Matcher::DataInputFactory<HttpMatchingData> {
178
public:
179
11987
  std::string name() const override { return "query_params"; }
180

            
181
  Matcher::DataInputFactoryCb<HttpMatchingData>
182
  createDataInputFactoryCb(const Protobuf::Message& config,
183
1
                           ProtobufMessage::ValidationVisitor& validation_visitor) override {
184
1
    const auto& typed_config = MessageUtil::downcastAndValidate<
185
1
        const envoy::type::matcher::v3::HttpRequestQueryParamMatchInput&>(config,
186
1
                                                                          validation_visitor);
187

            
188
1
    return [query_param = typed_config.query_param()] {
189
1
      return std::make_unique<HttpRequestQueryParamsDataInput>(query_param);
190
1
    };
191
1
  };
192
493
  ProtobufTypes::MessagePtr createEmptyConfigProto() override {
193
493
    return std::make_unique<envoy::type::matcher::v3::HttpRequestQueryParamMatchInput>();
194
493
  }
195
};
196

            
197
DECLARE_FACTORY(HttpRequestQueryParamsDataInputFactory);
198

            
199
} // namespace Matching
200
} // namespace Http
201
} // namespace Envoy