3
3
#include " envoy/http/filter.h"
4
4
#include " envoy/registry/registry.h"
5
5
6
+ #include " source/common/http/utility.h"
6
7
#include " source/extensions/filters/http/common/factory_base.h"
7
8
#include " source/extensions/filters/http/common/pass_through_filter.h"
8
9
@@ -27,14 +28,45 @@ class SetResponseCodeFilterConfig {
27
28
ThreadLocal::TypedSlot<> tls_slot_;
28
29
};
29
30
31
+ class SetResponseCodeFilterRouteSpecificConfig : public Envoy ::Router::RouteSpecificFilterConfig {
32
+ public:
33
+ SetResponseCodeFilterRouteSpecificConfig (const std::string& prefix, uint32_t code,
34
+ const std::string& body,
35
+ Server::Configuration::FactoryContextBase& context)
36
+ : prefix_(prefix), code_(code), body_(body), tls_slot_(context.threadLocal()) {}
37
+
38
+ const std::string prefix_;
39
+ const uint32_t code_;
40
+ const std::string body_;
41
+ // Allocate a slot to validate that it is destroyed on a main thread only.
42
+ ThreadLocal::TypedSlot<> tls_slot_;
43
+ };
44
+
30
45
class SetResponseCodeFilter : public Http ::PassThroughFilter {
31
46
public:
32
47
SetResponseCodeFilter (std::shared_ptr<SetResponseCodeFilterConfig> config) : config_(config) {}
33
48
34
49
Http::FilterHeadersStatus decodeHeaders (Http::RequestHeaderMap& headers, bool ) override {
35
- if (absl::StartsWith (headers.Path ()->value ().getStringView (), config_->prefix_ )) {
36
- decoder_callbacks_->sendLocalReply (static_cast <Http::Code>(config_->code_ ), config_->body_ ,
37
- nullptr , absl::nullopt, " " );
50
+ const auto * per_route_config = Envoy::Http::Utility::resolveMostSpecificPerFilterConfig<
51
+ SetResponseCodeFilterRouteSpecificConfig>(decoder_callbacks_);
52
+
53
+ std::string prefix;
54
+ uint32_t code;
55
+ std::string body;
56
+ // Route level config takes precedence over filter level config, if present.
57
+ if (per_route_config != nullptr ) {
58
+ prefix = per_route_config->prefix_ ;
59
+ code = per_route_config->code_ ;
60
+ body = per_route_config->body_ ;
61
+ } else {
62
+ prefix = config_->prefix_ ;
63
+ code = config_->code_ ;
64
+ body = config_->body_ ;
65
+ }
66
+
67
+ if (absl::StartsWith (headers.Path ()->value ().getStringView (), prefix)) {
68
+ decoder_callbacks_->sendLocalReply (static_cast <Http::Code>(code), body, nullptr ,
69
+ absl::nullopt, " " );
38
70
return Http::FilterHeadersStatus::StopIteration;
39
71
}
40
72
return Http::FilterHeadersStatus::Continue;
@@ -44,8 +76,10 @@ class SetResponseCodeFilter : public Http::PassThroughFilter {
44
76
const std::shared_ptr<SetResponseCodeFilterConfig> config_;
45
77
};
46
78
47
- class SetResponseCodeFilterFactory : public Extensions ::HttpFilters::Common::FactoryBase<
48
- test::integration::filters::SetResponseCodeFilterConfig> {
79
+ class SetResponseCodeFilterFactory
80
+ : public Extensions::HttpFilters::Common::FactoryBase<
81
+ test::integration::filters::SetResponseCodeFilterConfig,
82
+ test::integration::filters::SetResponseCodePerRouteFilterConfig> {
49
83
public:
50
84
SetResponseCodeFilterFactory () : FactoryBase(" set-response-code-filter" ) {}
51
85
@@ -68,6 +102,14 @@ class SetResponseCodeFilterFactory : public Extensions::HttpFilters::Common::Fac
68
102
callbacks.addStreamFilter (std::make_shared<SetResponseCodeFilter>(filter_config));
69
103
};
70
104
}
105
+
106
+ Router::RouteSpecificFilterConfigConstSharedPtr createRouteSpecificFilterConfigTyped (
107
+ const test::integration::filters::SetResponseCodePerRouteFilterConfig& proto_config,
108
+ Server::Configuration::ServerFactoryContext& context,
109
+ ProtobufMessage::ValidationVisitor&) override {
110
+ return std::make_shared<const SetResponseCodeFilterRouteSpecificConfig>(
111
+ proto_config.prefix (), proto_config.code (), proto_config.body (), context);
112
+ }
71
113
};
72
114
73
115
REGISTER_FACTORY (SetResponseCodeFilterFactory, Server::Configuration::NamedHttpFilterConfigFactory);
0 commit comments