Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -81,3 +81,14 @@ message ResponseMap {
//
config.core.v3.SubstitutionFormatString body_format = 2;
}

// Extra settings on a per virtualhost/route/weighted-cluster level.
message ResponseMapPerRoute {
oneof override {
option (validate.required) = true;

// Disable the response map filter for this particular vhost or route.
// If disabled is specified in multiple per-filter-configs, the most specific one will be used.
bool disabled = 1 [(validate.rules).bool = {const: true}];
Comment on lines 87 to 92
Copy link

@LukeShu LukeShu Oct 29, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see those validate. options on a few other filters (but not the grpc_http1_reverse_bridge filter that you mentioned cribbing the approach from), so I guess I trust that they're correct, but I'm flummoxed as to interpreting what they actually mean.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i tested this and it means disabled must be a bool equal to true. false is not valid.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why shouldn't false be valid? And if it's validate.required, then how do you omit it (I guess you just leave out the entire ResponseMapPerRoute?)?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i think the idea is to omit if you want it to be not disabled. it's opinionated for sure.

}
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions source/extensions/filters/http/response_map/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ envoy_cc_library(
"//include/envoy/http:codes_interface",
"//include/envoy/http:filter_interface",
"//source/common/response_map:response_map_lib",
"//source/extensions/filters/http:well_known_names",
"//source/common/buffer:buffer_lib",
"//source/common/common:assert_lib",
"//source/common/common:enum_to_int",
Expand Down
11 changes: 10 additions & 1 deletion source/extensions/filters/http/response_map/config.cc
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,23 @@ namespace ResponseMapFilter {

Http::FilterFactoryCb ResponseMapFilterFactory::createFilterFactoryFromProtoTyped(
const envoy::extensions::filters::http::response_map::v3::ResponseMap& proto_config,
const std::string& stats_prefix, Server::Configuration::FactoryContext& context) {
const std::string& stats_prefix,
Server::Configuration::FactoryContext& context) {
ResponseMapFilterConfigSharedPtr config =
std::make_shared<ResponseMapFilterConfig>(proto_config, stats_prefix, context);
return [config](Http::FilterChainFactoryCallbacks& callbacks) -> void {
callbacks.addStreamFilter(std::make_shared<ResponseMapFilter>(config));
};
}

Router::RouteSpecificFilterConfigConstSharedPtr
ResponseMapFilterFactory::createRouteSpecificFilterConfigTyped(
const envoy::extensions::filters::http::response_map::v3::ResponseMapPerRoute& proto_config,
Server::Configuration::ServerFactoryContext&,
ProtobufMessage::ValidationVisitor&) {
return std::make_shared<FilterConfigPerRoute>(proto_config);
}

/**
* Static registration for the response_map filter. @see RegisterFactory.
*/
Expand Down
10 changes: 9 additions & 1 deletion source/extensions/filters/http/response_map/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

#include "envoy/extensions/filters/http/response_map/v3/response_map.pb.h"
#include "envoy/extensions/filters/http/response_map/v3/response_map.pb.validate.h"
#include "envoy/server/filter_config.h"

#include "extensions/filters/http/common/factory_base.h"
#include "extensions/filters/http/well_known_names.h"
Expand All @@ -16,13 +17,20 @@ namespace ResponseMapFilter {
*/
class ResponseMapFilterFactory
: public Common::FactoryBase<
envoy::extensions::filters::http::response_map::v3::ResponseMap> {
envoy::extensions::filters::http::response_map::v3::ResponseMap,
envoy::extensions::filters::http::response_map::v3::ResponseMapPerRoute> {
public:
ResponseMapFilterFactory() : FactoryBase(HttpFilterNames::get().ResponseMap) {}

Http::FilterFactoryCb createFilterFactoryFromProtoTyped(
const envoy::extensions::filters::http::response_map::v3::ResponseMap& proto_config,
const std::string& stats_prefix, Server::Configuration::FactoryContext& context) override;

private:
Router::RouteSpecificFilterConfigConstSharedPtr createRouteSpecificFilterConfigTyped(
const envoy::extensions::filters::http::response_map::v3::ResponseMapPerRoute& proto_config,
Server::Configuration::ServerFactoryContext& context,
ProtobufMessage::ValidationVisitor& validator) override;
};

} // namespace ResponseMapFilter
Expand Down
50 changes: 44 additions & 6 deletions source/extensions/filters/http/response_map/response_map_filter.cc
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,14 @@
#include "envoy/http/codes.h"
#include "envoy/http/header_map.h"

#include "extensions/filters/http/well_known_names.h"

#include "common/common/empty_string.h"
#include "common/common/enum_to_int.h"
#include "common/common/logger.h"
#include "common/http/header_map_impl.h"
#include "common/http/headers.h"
#include "common/http/utility.h"

namespace Envoy {
namespace Extensions {
Expand All @@ -26,21 +29,44 @@ ResponseMapFilter::ResponseMapFilter(ResponseMapFilterConfigSharedPtr config)
Http::FilterHeadersStatus ResponseMapFilter::decodeHeaders(Http::RequestHeaderMap& request_headers,
bool end_stream) {
ENVOY_LOG(trace, "response map filter: decodeHeaders with end_stream = {}", end_stream);

// Disable filter per route config if applies
if (decoder_callbacks_->route() != nullptr) {
const auto* per_route_config =
Http::Utility::resolveMostSpecificPerFilterConfig<FilterConfigPerRoute>(
Extensions::HttpFilters::HttpFilterNames::get().ResponseMap,
decoder_callbacks_->route());
ENVOY_LOG(trace, "response map filter: found route. has per_route_config? {}",
per_route_config != nullptr);
if (per_route_config != nullptr && per_route_config->disabled()) {
ENVOY_LOG(trace, "response map filter: disabling due to per_route_config");
disabled_ = true;
return Http::FilterHeadersStatus::Continue;
}
}

request_headers_ = &request_headers;
return Http::FilterHeadersStatus::Continue;
}

Http::FilterHeadersStatus ResponseMapFilter::encodeHeaders(Http::ResponseHeaderMap& headers,
bool end_stream) {
ENVOY_LOG(trace, "response map filter: encodeHeaders with http status = {} and end_stream = {}",
headers.getStatusValue(), end_stream);
ENVOY_LOG(trace,
"response map filter: encodeHeaders with http status = {}, end_stream = {}, disabled = {}",
headers.getStatusValue(), end_stream, disabled_);

// If this filter is disabled, continue without doing anything.
if (disabled_) {
return Http::FilterHeadersStatus::Continue;
}

// Save a reference to the response headers. If we end up rewriting the response,
// we'll need to set the content-length (and possibly other) headers later.
response_headers_ = &headers;

// Check whether we should rewrite this response based on response headers.
do_rewrite_ = config_->response_map()->match(request_headers_, headers, encoder_callbacks_->streamInfo());
do_rewrite_ = config_->response_map()->match(
request_headers_, headers, encoder_callbacks_->streamInfo());
ENVOY_LOG(trace, "response map filter: do_rewrite_ {}", do_rewrite_);

// If we decided not to rewrite the response, simply pass through to other
Expand All @@ -61,9 +87,16 @@ Http::FilterHeadersStatus ResponseMapFilter::encodeHeaders(Http::ResponseHeaderM
return Http::FilterHeadersStatus::Continue;
}

Http::FilterDataStatus ResponseMapFilter::encodeData(Buffer::Instance& data, bool end_stream) {
ENVOY_LOG(trace, "response map filter: encodeData with data length {} and end_stream = {}",
data.length(), end_stream);
Http::FilterDataStatus ResponseMapFilter::encodeData(Buffer::Instance& data,
bool end_stream) {
ENVOY_LOG(trace,
"response map filter: encodeData with data length {}, end_stream = {}, disabled = {}",
data.length(), end_stream, disabled_);

// If this filter is disabled, continue without doing anything.
if (disabled_) {
return Http::FilterDataStatus::Continue;
}

// If we decided not to rewrite the response, simply pass through to other
// filters.
Expand Down Expand Up @@ -94,6 +127,11 @@ void ResponseMapFilter::doRewrite(void) {
ENVOY_LOG(trace, "response map filter: doRewrite with {} encoding_buffer",
encoding_buffer != nullptr ? "non-null" : "null");

// If this route is disabled, we should never be doing a rewrite.
// In fact, we never should have even checked if we should do
// a rewrite.
ASSERT(!disabled_);

// We should either see no encoding buffer or an empty encoding buffer.
//
// We'll see no encoding buffer if the upstream response was never observed
Expand Down
13 changes: 13 additions & 0 deletions source/extensions/filters/http/response_map/response_map_filter.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,18 @@ class ResponseMapFilterConfig {
};
using ResponseMapFilterConfigSharedPtr = std::shared_ptr<ResponseMapFilterConfig>;

class FilterConfigPerRoute : public Router::RouteSpecificFilterConfig {
public:
FilterConfigPerRoute(
const envoy::extensions::filters::http::response_map::v3::ResponseMapPerRoute&
config)
: disabled_(config.disabled()) {}
bool disabled() const { return disabled_; }

private:
bool disabled_;
};

class ResponseMapFilter : public Http::StreamFilter, Logger::Loggable<Logger::Id::filter> {
public:
ResponseMapFilter(ResponseMapFilterConfigSharedPtr config);
Expand Down Expand Up @@ -71,6 +83,7 @@ class ResponseMapFilter : public Http::StreamFilter, Logger::Loggable<Logger::Id
Http::ResponseHeaderMap* response_headers_{};
Http::RequestHeaderMap* request_headers_{};
bool do_rewrite_{};
bool disabled_{};
};

} // namespace ResponseMapFilter
Expand Down