From 899ec21309e97214241b3951c9de9766611125fa Mon Sep 17 00:00:00 2001 From: Lukasz Dziedziak Date: Mon, 12 Aug 2019 20:19:10 +0200 Subject: [PATCH 01/20] Init work with configuration proposition Signed-off-by: Lukasz Dziedziak --- .../network/http_connection_manager/v2/BUILD | 4 +++ .../v2/http_connection_manager.proto | 31 +++++++++++++++++++ api/envoy/data/accesslog/v2/BUILD | 1 + 3 files changed, 36 insertions(+) diff --git a/api/envoy/config/filter/network/http_connection_manager/v2/BUILD b/api/envoy/config/filter/network/http_connection_manager/v2/BUILD index 95d3811f426af..5b8fc45473f81 100644 --- a/api/envoy/config/filter/network/http_connection_manager/v2/BUILD +++ b/api/envoy/config/filter/network/http_connection_manager/v2/BUILD @@ -12,7 +12,9 @@ api_proto_library_internal( "//envoy/api/v2/core:config_source", "//envoy/api/v2/core:protocol", "//envoy/config/filter/accesslog/v2:accesslog", + "//envoy/data/accesslog/v2:accesslog", "//envoy/type:percent", + "//envoy/type/matcher:string", ], ) @@ -26,6 +28,8 @@ api_go_proto_library( "//envoy/api/v2/core:config_source_go_proto", "//envoy/api/v2/core:protocol_go_proto", "//envoy/config/filter/accesslog/v2:accesslog_go_proto", + "//envoy/data/accesslog/v2:accesslog_go_proto", "//envoy/type:percent_go_proto", + "//envoy/type/matcher:string_go_proto", ], ) diff --git a/api/envoy/config/filter/network/http_connection_manager/v2/http_connection_manager.proto b/api/envoy/config/filter/network/http_connection_manager/v2/http_connection_manager.proto index 4d662fc2c5244..4b7d354ca98a6 100644 --- a/api/envoy/config/filter/network/http_connection_manager/v2/http_connection_manager.proto +++ b/api/envoy/config/filter/network/http_connection_manager/v2/http_connection_manager.proto @@ -12,7 +12,9 @@ import "envoy/api/v2/core/protocol.proto"; import "envoy/api/v2/rds.proto"; import "envoy/api/v2/srds.proto"; import "envoy/config/filter/accesslog/v2/accesslog.proto"; +import "envoy/data/accesslog/v2/accesslog.proto"; import "envoy/type/percent.proto"; +import "envoy/type/matcher/string.proto"; import "google/protobuf/any.proto"; import "google/protobuf/duration.proto"; @@ -432,6 +434,35 @@ message HttpConnectionManager { // with `prefix` match set to `/dir`. Defaults to `false`. Note that slash merging is not part of // `HTTP spec ` and is provided for convenience. bool merge_slashes = 33; + + // Configuration of local reply send by envoy for http responses. Allows to define custom rules + // which maps response attribute returned by envoy to different one. Currently mapping of + // status code is implemented. + message SendLocalReplyConfig { + // Configuration which allows to define custom rules for matching local response. + // It works like and operator e.g: if you define status code 404 and body pattern + // then response must match both + message Match { + // Definition of status codes to match. + repeated uint32 status_codes = 1; + // Definition of body pattern to match. + envoy.type.matcher.StringMatcher body_pattern = 2; + // Definition of response flags to match. + envoy.data.accesslog.v2.ResponseFlags response_flags = 3; + }; + + // Configuration which allows to define custom mapping for matched response. + message Rewrite { + // Definition of status code to which matched one will be mapped. + uint32 status = 1 [(validate.rules).uint32 = {gte: 100, lt: 600}]; + }; + + Match match = 1; + Rewrite rewrite = 2; + }; + + repeated SendLocalReplyConfig send_local_reply_config = 34; + } message Rds { diff --git a/api/envoy/data/accesslog/v2/BUILD b/api/envoy/data/accesslog/v2/BUILD index d3ade88e922f8..e3fb0d0ccea7a 100644 --- a/api/envoy/data/accesslog/v2/BUILD +++ b/api/envoy/data/accesslog/v2/BUILD @@ -7,6 +7,7 @@ api_proto_library_internal( srcs = ["accesslog.proto"], visibility = [ "//envoy/service/accesslog/v2:__pkg__", + "//envoy/config/filter/network/http_connection_manager/v2:__pkg__", ], deps = [ "//envoy/api/v2/core:address", From 6da905d4a40540a48b09bbe341eb073c8af682a8 Mon Sep 17 00:00:00 2001 From: Lukasz Dziedziak Date: Sat, 31 Aug 2019 10:54:27 +0200 Subject: [PATCH 02/20] Added missing dependency Signed-off-by: Lukasz Dziedziak --- source/common/http/BUILD | 8 +++++++ source/common/http/local_reply.h | 37 ++++++++++++++++++++++++++++++++ 2 files changed, 45 insertions(+) create mode 100644 source/common/http/local_reply.h diff --git a/source/common/http/BUILD b/source/common/http/BUILD index 1dcf5045fa261..63c9a1269f90a 100644 --- a/source/common/http/BUILD +++ b/source/common/http/BUILD @@ -236,6 +236,14 @@ envoy_cc_library( ], ) +envoy_cc_library( + name = "local_reply_lib", + hdrs = ["local_reply.h"], + deps = [ + "//source/common/common:matchers_lib", + ], +) + envoy_cc_library( name = "message_lib", srcs = ["message_impl.cc"], diff --git a/source/common/http/local_reply.h b/source/common/http/local_reply.h new file mode 100644 index 0000000000000..fb60efd734cfd --- /dev/null +++ b/source/common/http/local_reply.h @@ -0,0 +1,37 @@ +#pragma once + +#include +#include + +#include "common/common/matchers.h" + +namespace Envoy { +namespace Http{ + +struct LocalReplyMatcher { + std::list status_; + Matchers::StringMatcher body_pattern_; + uint64_t response_flags_; +}; + +/** + * Structure which holds rewriter configuration from proto file for LocalReplyConfig. + */ +struct LocalReplyRewriter { + uint32_t status_; +}; + +class LocalReplyConfig { + public: + LocalReplyConfig( + std::list>& match_rewrite_pair_list) + : match_rewrite_pair_list_(match_rewrite_pair_list){}; + + private: + std::list> match_rewrite_pair_list_; +} + +using LocalReplyConfigConstPtr = std::unique_ptr; + +} // namespace Http +} // namespace Envoy From 9bf0e6bcd7f41b6cbd0d762df5623f7b814474e7 Mon Sep 17 00:00:00 2001 From: Lukasz Dziedziak Date: Sat, 31 Aug 2019 23:19:18 +0200 Subject: [PATCH 03/20] Without passed config Signed-off-by: Lukasz Dziedziak --- .../v2/http_connection_manager.proto | 4 +-- source/common/http/BUILD | 1 + source/common/http/conn_manager_config.h | 6 ++++ source/common/http/local_reply.h | 32 +++++++++++++++---- .../network/http_connection_manager/BUILD | 1 + .../network/http_connection_manager/config.cc | 21 ++++++++++++ .../network/http_connection_manager/config.h | 5 +++ source/extensions/filters/network/kafka/BUILD | 1 + source/server/http/admin.h | 1 + 9 files changed, 64 insertions(+), 8 deletions(-) diff --git a/api/envoy/config/filter/network/http_connection_manager/v2/http_connection_manager.proto b/api/envoy/config/filter/network/http_connection_manager/v2/http_connection_manager.proto index 1b6b93a8843c5..65ddb3c8627db 100644 --- a/api/envoy/config/filter/network/http_connection_manager/v2/http_connection_manager.proto +++ b/api/envoy/config/filter/network/http_connection_manager/v2/http_connection_manager.proto @@ -27,7 +27,7 @@ import "gogoproto/gogo.proto"; // [#protodoc-title: HTTP connection manager] // HTTP connection manager :ref:`configuration overview `. -// [#comment:next free field: 35] +// [#comment:next free field: 36] message HttpConnectionManager { enum CodecType { option (gogoproto.goproto_enum_prefix) = false; @@ -479,7 +479,7 @@ message HttpConnectionManager { Rewrite rewrite = 2; }; - repeated SendLocalReplyConfig send_local_reply_config = 34; + repeated SendLocalReplyConfig send_local_reply_config = 35; } diff --git a/source/common/http/BUILD b/source/common/http/BUILD index 35164e5b0f2fc..f7aae23a9fbe8 100644 --- a/source/common/http/BUILD +++ b/source/common/http/BUILD @@ -124,6 +124,7 @@ envoy_cc_library( "//include/envoy/http:filter_interface", "//include/envoy/router:rds_interface", "//source/common/network:utility_lib", + "//source/common/http:local_reply_lib" ], ) diff --git a/source/common/http/conn_manager_config.h b/source/common/http/conn_manager_config.h index b32d8f520e409..cf718ac656872 100644 --- a/source/common/http/conn_manager_config.h +++ b/source/common/http/conn_manager_config.h @@ -8,6 +8,7 @@ #include "common/http/date_provider.h" #include "common/network/utility.h" +#include "common/http/local_reply.h" namespace Envoy { namespace Http { @@ -368,6 +369,11 @@ class ConnectionManagerConfig { * one. */ virtual bool shouldMergeSlashes() const PURE; + + /** + * @return supplies the local reply mapping configuration + */ + virtual const LocalReplyConfig* localReplyConfig() const PURE; }; } // namespace Http } // namespace Envoy diff --git a/source/common/http/local_reply.h b/source/common/http/local_reply.h index fb60efd734cfd..72ab0d54e38ee 100644 --- a/source/common/http/local_reply.h +++ b/source/common/http/local_reply.h @@ -2,16 +2,31 @@ #include #include +#include + #include "common/common/matchers.h" namespace Envoy { namespace Http{ -struct LocalReplyMatcher { - std::list status_; - Matchers::StringMatcher body_pattern_; - uint64_t response_flags_; + // const envoy::type::matcher::StringMatcher& body_pattern, + // const envoy::data::accesslog::v2::ResponseFlags& response_flags +struct LocalReplyMatcher { + LocalReplyMatcher( + std::vector& status_codes, + const envoy::type::matcher::StringMatcher& body_pattern + ): status_codes_(move(status_codes)), body_pattern_(body_pattern){ + }; + + bool match(const absl::string_view value){ + return body_pattern_.match(value); + } + + std::vector status_codes_; + +Matchers::StringMatcherImpl body_pattern_; + // uint64_t response_flags_; }; /** @@ -25,11 +40,16 @@ class LocalReplyConfig { public: LocalReplyConfig( std::list>& match_rewrite_pair_list) - : match_rewrite_pair_list_(match_rewrite_pair_list){}; + : match_rewrite_pair_list_(match_rewrite_pair_list){ + + LocalReplyMatcher* test = & match_rewrite_pair_list.front().first; + test->match("test"); + std::cout << "Test" << test->match("test") << '\n' ; + }; private: std::list> match_rewrite_pair_list_; -} +}; using LocalReplyConfigConstPtr = std::unique_ptr; diff --git a/source/extensions/filters/network/http_connection_manager/BUILD b/source/extensions/filters/network/http_connection_manager/BUILD index fbe72b257b158..59f4d79b214da 100644 --- a/source/extensions/filters/network/http_connection_manager/BUILD +++ b/source/extensions/filters/network/http_connection_manager/BUILD @@ -34,6 +34,7 @@ envoy_cc_library( "//source/common/http:utility_lib", "//source/common/http/http1:codec_lib", "//source/common/http/http2:codec_lib", + "//source/common/http:local_reply_lib", "//source/common/json:json_loader_lib", "//source/common/protobuf:utility_lib", "//source/common/router:rds_lib", diff --git a/source/extensions/filters/network/http_connection_manager/config.cc b/source/extensions/filters/network/http_connection_manager/config.cc index 81a45e9347619..acbe0669144d1 100644 --- a/source/extensions/filters/network/http_connection_manager/config.cc +++ b/source/extensions/filters/network/http_connection_manager/config.cc @@ -341,6 +341,27 @@ HttpConnectionManagerConfig::HttpConnectionManagerConfig( std::make_pair(name, FilterConfig{std::move(factories), enabled})); } } + if (config.send_local_reply_config().size() > 0) { + std::list> + list_of_pairs; + for (auto& match_rewrite_config : config.send_local_reply_config()) { + std::vector status_codes; + for (auto code : match_rewrite_config.match().status_codes()) { + status_codes.emplace_back(code); + } + + std::pair pair = + std::make_pair( + Http::LocalReplyMatcher{status_codes, match_rewrite_config.match().body_pattern()}, + // , + // match_rewrite_config.match().body_pattern(), + // match_rewrite_config.match().response_flags()}, + Http::LocalReplyRewriter{match_rewrite_config.rewrite().status()}); + list_of_pairs.emplace_back(std::move(pair)); + } + local_reply_config_ = Http::LocalReplyConfigConstPtr( + new Http::LocalReplyConfig(list_of_pairs)); + } } void HttpConnectionManagerConfig::processFilter( diff --git a/source/extensions/filters/network/http_connection_manager/config.h b/source/extensions/filters/network/http_connection_manager/config.h index 0385762236c1d..3a8062e085ea1 100644 --- a/source/extensions/filters/network/http_connection_manager/config.h +++ b/source/extensions/filters/network/http_connection_manager/config.h @@ -15,6 +15,7 @@ #include "common/common/logger.h" #include "common/http/conn_manager_impl.h" #include "common/json/json_loader.h" +#include "common/http/local_reply.h" #include "extensions/filters/network/common/factory_base.h" #include "extensions/filters/network/well_known_names.h" @@ -142,6 +143,9 @@ class HttpConnectionManagerConfig : Logger::Loggable, const Http::Http1Settings& http1Settings() const override { return http1_settings_; } bool shouldNormalizePath() const override { return normalize_path_; } bool shouldMergeSlashes() const override { return merge_slashes_; } + const Http::LocalReplyConfig* localReplyConfig() const override { + return local_reply_config_.get(); + } std::chrono::milliseconds delayedCloseTimeout() const override { return delayed_close_timeout_; } private: @@ -189,6 +193,7 @@ class HttpConnectionManagerConfig : Logger::Loggable, std::chrono::milliseconds delayed_close_timeout_; const bool normalize_path_; const bool merge_slashes_; + Http::LocalReplyConfigConstPtr local_reply_config_; // Default idle timeout is 5 minutes if nothing is specified in the HCM config. static const uint64_t StreamIdleTimeoutMs = 5 * 60 * 1000; diff --git a/source/extensions/filters/network/kafka/BUILD b/source/extensions/filters/network/kafka/BUILD index 8ff831a0274cb..92202ff7e538b 100644 --- a/source/extensions/filters/network/kafka/BUILD +++ b/source/extensions/filters/network/kafka/BUILD @@ -26,6 +26,7 @@ envoy_cc_library( name = "kafka_request_codec_lib", srcs = ["request_codec.cc"], hdrs = [ + "codec.h", "request_codec.h", ], deps = [ diff --git a/source/server/http/admin.h b/source/server/http/admin.h index f54d72fee7ff3..9d1d8bf29f217 100644 --- a/source/server/http/admin.h +++ b/source/server/http/admin.h @@ -147,6 +147,7 @@ class AdminImpl : public Admin, const Http::Http1Settings& http1Settings() const override { return http1_settings_; } bool shouldNormalizePath() const override { return true; } bool shouldMergeSlashes() const override { return true; } + Http::LocalReplyConfig* localReplyConfig() const override { return nullptr; } Http::Code request(absl::string_view path_and_query, absl::string_view method, Http::HeaderMap& response_headers, std::string& body) override; void closeSocket(); From fc3c54582e57c39d6e66631a4a6c8504441c9725 Mon Sep 17 00:00:00 2001 From: Lukasz Dziedziak Date: Mon, 2 Sep 2019 19:50:12 +0200 Subject: [PATCH 04/20] WIP config Signed-off-by: Lukasz Dziedziak --- source/common/http/BUILD | 1 + source/common/http/local_reply.h | 34 +++++++++++++------ .../network/http_connection_manager/config.cc | 20 +---------- 3 files changed, 25 insertions(+), 30 deletions(-) diff --git a/source/common/http/BUILD b/source/common/http/BUILD index f7aae23a9fbe8..7df61ad039d83 100644 --- a/source/common/http/BUILD +++ b/source/common/http/BUILD @@ -244,6 +244,7 @@ envoy_cc_library( hdrs = ["local_reply.h"], deps = [ "//source/common/common:matchers_lib", + "@envoy_api//envoy/config/filter/network/http_connection_manager/v2:http_connection_manager_cc", ], ) diff --git a/source/common/http/local_reply.h b/source/common/http/local_reply.h index 72ab0d54e38ee..ae2f84dd640c5 100644 --- a/source/common/http/local_reply.h +++ b/source/common/http/local_reply.h @@ -6,6 +6,7 @@ #include "common/common/matchers.h" +#include "envoy/config/filter/network/http_connection_manager/v2/http_connection_manager.pb.validate.h" namespace Envoy { namespace Http{ @@ -13,13 +14,11 @@ namespace Http{ // const envoy::type::matcher::StringMatcher& body_pattern, // const envoy::data::accesslog::v2::ResponseFlags& response_flags struct LocalReplyMatcher { - LocalReplyMatcher( - std::vector& status_codes, - const envoy::type::matcher::StringMatcher& body_pattern - ): status_codes_(move(status_codes)), body_pattern_(body_pattern){ - }; + LocalReplyMatcher(std::vector& status_codes, + const envoy::type::matcher::StringMatcher& body_pattern): status_codes_(move(status_codes)), + body_pattern_(body_pattern){}; - bool match(const absl::string_view value){ + bool match(const absl::string_view value) const{ return body_pattern_.match(value); } @@ -39,14 +38,27 @@ struct LocalReplyRewriter { class LocalReplyConfig { public: LocalReplyConfig( - std::list>& match_rewrite_pair_list) - : match_rewrite_pair_list_(match_rewrite_pair_list){ + const envoy::config::filter::network::http_connection_manager::v2::HttpConnectionManager& config + ){ + for (const auto& match_rewrite_config : config.send_local_reply_config()) { + std::vector status_codes; + for (const auto code : match_rewrite_config.match().status_codes()) { + status_codes.emplace_back(code); + } + + std::pair pair = + std::make_pair( + Http::LocalReplyMatcher{status_codes, match_rewrite_config.match().body_pattern()}, + Http::LocalReplyRewriter{match_rewrite_config.rewrite().status()}); + match_rewrite_pair_list_.emplace_back(std::move(pair)); - LocalReplyMatcher* test = & match_rewrite_pair_list.front().first; - test->match("test"); - std::cout << "Test" << test->match("test") << '\n' ; + } }; + bool match(const absl::string_view value) const{ + return match_rewrite_pair_list_.front().first.match(value); + } + private: std::list> match_rewrite_pair_list_; }; diff --git a/source/extensions/filters/network/http_connection_manager/config.cc b/source/extensions/filters/network/http_connection_manager/config.cc index acbe0669144d1..f856a29c71fad 100644 --- a/source/extensions/filters/network/http_connection_manager/config.cc +++ b/source/extensions/filters/network/http_connection_manager/config.cc @@ -342,25 +342,7 @@ HttpConnectionManagerConfig::HttpConnectionManagerConfig( } } if (config.send_local_reply_config().size() > 0) { - std::list> - list_of_pairs; - for (auto& match_rewrite_config : config.send_local_reply_config()) { - std::vector status_codes; - for (auto code : match_rewrite_config.match().status_codes()) { - status_codes.emplace_back(code); - } - - std::pair pair = - std::make_pair( - Http::LocalReplyMatcher{status_codes, match_rewrite_config.match().body_pattern()}, - // , - // match_rewrite_config.match().body_pattern(), - // match_rewrite_config.match().response_flags()}, - Http::LocalReplyRewriter{match_rewrite_config.rewrite().status()}); - list_of_pairs.emplace_back(std::move(pair)); - } - local_reply_config_ = Http::LocalReplyConfigConstPtr( - new Http::LocalReplyConfig(list_of_pairs)); + local_reply_config_ = Http::LocalReplyConfigConstPtr(new Http::LocalReplyConfig(config)); } } From c9a686e62bc83c29174c6ec69feb38df4b88b8d9 Mon Sep 17 00:00:00 2001 From: Lukasz Dziedziak Date: Tue, 3 Sep 2019 15:20:30 +0200 Subject: [PATCH 05/20] Response flags added Signed-off-by: Lukasz Dziedziak --- .../v2/http_connection_manager.proto | 1 - api/envoy/data/accesslog/v2/BUILD | 2 +- source/common/http/BUILD | 3 +- source/common/http/local_reply.h | 138 +++++++++++++----- .../network/http_connection_manager/BUILD | 2 +- .../network/http_connection_manager/config.h | 4 +- 6 files changed, 109 insertions(+), 41 deletions(-) diff --git a/api/envoy/config/filter/network/http_connection_manager/v2/http_connection_manager.proto b/api/envoy/config/filter/network/http_connection_manager/v2/http_connection_manager.proto index 65ddb3c8627db..8bf8f559d17f0 100644 --- a/api/envoy/config/filter/network/http_connection_manager/v2/http_connection_manager.proto +++ b/api/envoy/config/filter/network/http_connection_manager/v2/http_connection_manager.proto @@ -480,7 +480,6 @@ message HttpConnectionManager { }; repeated SendLocalReplyConfig send_local_reply_config = 35; - } message Rds { diff --git a/api/envoy/data/accesslog/v2/BUILD b/api/envoy/data/accesslog/v2/BUILD index e3fb0d0ccea7a..d3c7fa438da4c 100644 --- a/api/envoy/data/accesslog/v2/BUILD +++ b/api/envoy/data/accesslog/v2/BUILD @@ -6,8 +6,8 @@ api_proto_library_internal( name = "accesslog", srcs = ["accesslog.proto"], visibility = [ - "//envoy/service/accesslog/v2:__pkg__", "//envoy/config/filter/network/http_connection_manager/v2:__pkg__", + "//envoy/service/accesslog/v2:__pkg__", ], deps = [ "//envoy/api/v2/core:address", diff --git a/source/common/http/BUILD b/source/common/http/BUILD index 7df61ad039d83..9ec53a50073ed 100644 --- a/source/common/http/BUILD +++ b/source/common/http/BUILD @@ -123,8 +123,8 @@ envoy_cc_library( "//include/envoy/config:config_provider_interface", "//include/envoy/http:filter_interface", "//include/envoy/router:rds_interface", + "//source/common/http:local_reply_lib", "//source/common/network:utility_lib", - "//source/common/http:local_reply_lib" ], ) @@ -245,6 +245,7 @@ envoy_cc_library( deps = [ "//source/common/common:matchers_lib", "@envoy_api//envoy/config/filter/network/http_connection_manager/v2:http_connection_manager_cc", + "@envoy_api//envoy/service/accesslog/v2:als_cc", ], ) diff --git a/source/common/http/local_reply.h b/source/common/http/local_reply.h index ae2f84dd640c5..2e4f831e93a4c 100644 --- a/source/common/http/local_reply.h +++ b/source/common/http/local_reply.h @@ -1,31 +1,106 @@ #pragma once -#include #include +#include #include +#include "envoy/config/filter/network/http_connection_manager/v2/http_connection_manager.pb.validate.h" +#include "envoy/config/filter/accesslog/v2/accesslog.pb.validate.h" #include "common/common/matchers.h" -#include "envoy/config/filter/network/http_connection_manager/v2/http_connection_manager.pb.validate.h" namespace Envoy { -namespace Http{ +namespace Http { + static uint64_t toBitMask(const envoy::data::accesslog::v2::ResponseFlags& response_flags){ + uint64_t bit_mask = 0; + if (response_flags.failed_local_healthcheck()) { + bit_mask |= StreamInfo::ResponseFlag::FailedLocalHealthCheck; + } + + if (response_flags.no_healthy_upstream()) { + bit_mask |= StreamInfo::ResponseFlag::NoHealthyUpstream; + } + + if (response_flags.upstream_request_timeout()) { + bit_mask |= StreamInfo::ResponseFlag::UpstreamRequestTimeout; + } + + if (response_flags.local_reset()) { + bit_mask |= StreamInfo::ResponseFlag::LocalReset; + } + + if (response_flags.upstream_remote_reset()) { + bit_mask |= StreamInfo::ResponseFlag::UpstreamRemoteReset; + } + + if (response_flags.upstream_connection_failure()) { + bit_mask |= StreamInfo::ResponseFlag::UpstreamConnectionFailure; + } + + if (response_flags.upstream_connection_termination()) { + bit_mask |= StreamInfo::ResponseFlag::UpstreamConnectionTermination; + } + + if (response_flags.upstream_overflow()) { + bit_mask |= StreamInfo::ResponseFlag::UpstreamOverflow; + } + + if (response_flags.no_route_found()) { + bit_mask |= StreamInfo::ResponseFlag::NoRouteFound; + } + + if (response_flags.delay_injected()) { + bit_mask |= StreamInfo::ResponseFlag::DelayInjected; + } + + if (response_flags.fault_injected()) { + bit_mask |= StreamInfo::ResponseFlag::FaultInjected; + } + + if (response_flags.rate_limited()) { + bit_mask |= StreamInfo::ResponseFlag::RateLimited; + } + + // if (response_flags.unauthorized_details()) { + // bit_mask |= StreamInfo::ResponseFlag::UnauthorizedExternalService; + // } + + if (response_flags.rate_limit_service_error()) { + bit_mask |= StreamInfo::ResponseFlag::RateLimitServiceError; + } + + if (response_flags.downstream_connection_termination()) { + bit_mask |= StreamInfo::ResponseFlag::DownstreamConnectionTermination; + } + + if (response_flags.upstream_retry_limit_exceeded()) { + bit_mask |= StreamInfo::ResponseFlag::UpstreamRetryLimitExceeded; + } + + if (response_flags.stream_idle_timeout()) { + bit_mask |= StreamInfo::ResponseFlag::StreamIdleTimeout; + } + + if (response_flags.invalid_envoy_request_headers()) { + bit_mask |= StreamInfo::ResponseFlag::InvalidEnvoyRequestHeaders; + } + + return bit_mask; + } - // const envoy::type::matcher::StringMatcher& body_pattern, - // const envoy::data::accesslog::v2::ResponseFlags& response_flags struct LocalReplyMatcher { LocalReplyMatcher(std::vector& status_codes, - const envoy::type::matcher::StringMatcher& body_pattern): status_codes_(move(status_codes)), - body_pattern_(body_pattern){}; + const envoy::type::matcher::StringMatcher& body_pattern, + const envoy::data::accesslog::v2::ResponseFlags& response_flags) + : status_codes_(move(status_codes)), body_pattern_(body_pattern), response_flags_(toBitMask(response_flags)){}; - bool match(const absl::string_view value) const{ - return body_pattern_.match(value); + bool match(const absl::string_view value) const { + return body_pattern_.match(value); } std::vector status_codes_; - -Matchers::StringMatcherImpl body_pattern_; - // uint64_t response_flags_; + Matchers::StringMatcherImpl body_pattern_; + uint64_t response_flags_; }; /** @@ -36,31 +111,24 @@ struct LocalReplyRewriter { }; class LocalReplyConfig { - public: - LocalReplyConfig( - const envoy::config::filter::network::http_connection_manager::v2::HttpConnectionManager& config - ){ - for (const auto& match_rewrite_config : config.send_local_reply_config()) { - std::vector status_codes; - for (const auto code : match_rewrite_config.match().status_codes()) { - status_codes.emplace_back(code); - } - - std::pair pair = - std::make_pair( - Http::LocalReplyMatcher{status_codes, match_rewrite_config.match().body_pattern()}, - Http::LocalReplyRewriter{match_rewrite_config.rewrite().status()}); - match_rewrite_pair_list_.emplace_back(std::move(pair)); - +public: + LocalReplyConfig( + const envoy::config::filter::network::http_connection_manager::v2::HttpConnectionManager& + config) { + for (const auto& match_rewrite_config : config.send_local_reply_config()) { + std::vector status_codes; + for (const auto code : match_rewrite_config.match().status_codes()) { + status_codes.emplace_back(code); } - }; - - bool match(const absl::string_view value) const{ - return match_rewrite_pair_list_.front().first.match(value); - } - private: - std::list> match_rewrite_pair_list_; + std::pair pair = std::make_pair( + LocalReplyMatcher{status_codes, match_rewrite_config.match().body_pattern(), match_rewrite_config.match().response_flags()}, + LocalReplyRewriter{match_rewrite_config.rewrite().status()}); + match_rewrite_pair_list_.emplace_back(std::move(pair)); + } + }; +private: + std::list> match_rewrite_pair_list_; }; using LocalReplyConfigConstPtr = std::unique_ptr; diff --git a/source/extensions/filters/network/http_connection_manager/BUILD b/source/extensions/filters/network/http_connection_manager/BUILD index 59f4d79b214da..e297d8ed2447e 100644 --- a/source/extensions/filters/network/http_connection_manager/BUILD +++ b/source/extensions/filters/network/http_connection_manager/BUILD @@ -31,10 +31,10 @@ envoy_cc_library( "//source/common/config:utility_lib", "//source/common/http:conn_manager_lib", "//source/common/http:default_server_string_lib", + "//source/common/http:local_reply_lib", "//source/common/http:utility_lib", "//source/common/http/http1:codec_lib", "//source/common/http/http2:codec_lib", - "//source/common/http:local_reply_lib", "//source/common/json:json_loader_lib", "//source/common/protobuf:utility_lib", "//source/common/router:rds_lib", diff --git a/source/extensions/filters/network/http_connection_manager/config.h b/source/extensions/filters/network/http_connection_manager/config.h index 3a8062e085ea1..4e0b9d369fb7c 100644 --- a/source/extensions/filters/network/http_connection_manager/config.h +++ b/source/extensions/filters/network/http_connection_manager/config.h @@ -14,8 +14,8 @@ #include "common/common/logger.h" #include "common/http/conn_manager_impl.h" -#include "common/json/json_loader.h" #include "common/http/local_reply.h" +#include "common/json/json_loader.h" #include "extensions/filters/network/common/factory_base.h" #include "extensions/filters/network/well_known_names.h" @@ -193,7 +193,7 @@ class HttpConnectionManagerConfig : Logger::Loggable, std::chrono::milliseconds delayed_close_timeout_; const bool normalize_path_; const bool merge_slashes_; - Http::LocalReplyConfigConstPtr local_reply_config_; + Http::LocalReplyConfigConstPtr local_reply_config_; // Default idle timeout is 5 minutes if nothing is specified in the HCM config. static const uint64_t StreamIdleTimeoutMs = 5 * 60 * 1000; From 4213f2e9c0b15afd29af26d9eea5007ed6b08e22 Mon Sep 17 00:00:00 2001 From: Lukasz Dziedziak Date: Wed, 4 Sep 2019 18:09:17 +0200 Subject: [PATCH 06/20] Applied changes from code review Signed-off-by: Lukasz Dziedziak --- .../v2/http_connection_manager.proto | 22 +++++++++++++------ 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/api/envoy/config/filter/network/http_connection_manager/v2/http_connection_manager.proto b/api/envoy/config/filter/network/http_connection_manager/v2/http_connection_manager.proto index 8bf8f559d17f0..e0bfc7590a0cd 100644 --- a/api/envoy/config/filter/network/http_connection_manager/v2/http_connection_manager.proto +++ b/api/envoy/config/filter/network/http_connection_manager/v2/http_connection_manager.proto @@ -461,20 +461,28 @@ message HttpConnectionManager { // It works like and operator e.g: if you define status code 404 and body pattern // then response must match both message Match { - // Definition of status codes to match. - repeated uint32 status_codes = 1; - // Definition of body pattern to match. - envoy.type.matcher.StringMatcher body_pattern = 2; - // Definition of response flags to match. - envoy.data.accesslog.v2.ResponseFlags response_flags = 3; + oneof matcher_specifier{ + // Definition of status codes to match. + google.protobuf.UInt32Value status_codes = 1; + // Definition of body pattern to match. + envoy.type.matcher.StringMatcher body_pattern = 2; + // Definition of response flags to match. + envoy.data.accesslog.v2.ResponseFlags response_flags = 3; + // Definiton of and matcher which combine all defined rules in logical AND operation + AndMatcher and_matcher = 4; + } }; // Configuration which allows to define custom mapping for matched response. message Rewrite { // Definition of status code to which matched one will be mapped. - uint32 status = 1 [(validate.rules).uint32 = {gte: 100, lt: 600}]; + google.protobuf.UInt32Value status = 1; }; + message AndMatcher { + repeated Match matchers = 1 [(validate.rules).repeated .min_items = 2]; + } + Match match = 1; Rewrite rewrite = 2; }; From f8df3ae639ac4fe5379cfd8d8d5b8cc56c341ae9 Mon Sep 17 00:00:00 2001 From: Lukasz Dziedziak Date: Wed, 4 Sep 2019 18:13:02 +0200 Subject: [PATCH 07/20] repeated match Signed-off-by: Lukasz Dziedziak --- .../http_connection_manager/v2/http_connection_manager.proto | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/envoy/config/filter/network/http_connection_manager/v2/http_connection_manager.proto b/api/envoy/config/filter/network/http_connection_manager/v2/http_connection_manager.proto index e0bfc7590a0cd..9eb38e4d3dad2 100644 --- a/api/envoy/config/filter/network/http_connection_manager/v2/http_connection_manager.proto +++ b/api/envoy/config/filter/network/http_connection_manager/v2/http_connection_manager.proto @@ -483,7 +483,7 @@ message HttpConnectionManager { repeated Match matchers = 1 [(validate.rules).repeated .min_items = 2]; } - Match match = 1; + repeated Match match = 1; Rewrite rewrite = 2; }; From 052aeeb22bad5ba45b7cff5e771dfd9072e11a00 Mon Sep 17 00:00:00 2001 From: Lukasz Dziedziak Date: Sat, 7 Sep 2019 11:04:19 +0200 Subject: [PATCH 08/20] WIP local reply formatter with access log reuse Signed-off-by: Lukasz Dziedziak --- .../network/http_connection_manager/v2/BUILD | 2 - .../v2/http_connection_manager.proto | 50 ++----- api/envoy/data/accesslog/v2/BUILD | 1 - include/envoy/access_log/access_log.h | 6 +- include/envoy/http/BUILD | 8 + include/envoy/http/local_reply.h | 27 ++++ .../common/access_log/access_log_formatter.cc | 50 +++++-- .../common/access_log/access_log_formatter.h | 37 +++-- source/common/http/BUILD | 16 +- source/common/http/async_client_impl.h | 5 + source/common/http/conn_manager_config.h | 8 +- source/common/http/conn_manager_impl.cc | 15 +- source/common/http/local_reply.h | 137 ------------------ source/common/http/local_reply_formatter.cc | 30 ++++ source/common/http/local_reply_formatter.h | 32 ++++ source/common/http/utility.cc | 21 ++- source/common/http/utility.h | 1 + source/common/router/header_formatter.cc | 2 +- .../file/file_access_log_impl.cc | 2 +- .../network/http_connection_manager/BUILD | 2 +- .../network/http_connection_manager/config.cc | 43 +++++- .../network/http_connection_manager/config.h | 8 +- source/extensions/filters/network/kafka/BUILD | 2 +- source/server/http/admin.h | 2 +- 24 files changed, 275 insertions(+), 232 deletions(-) create mode 100644 include/envoy/http/local_reply.h delete mode 100644 source/common/http/local_reply.h create mode 100644 source/common/http/local_reply_formatter.cc create mode 100644 source/common/http/local_reply_formatter.h diff --git a/api/envoy/config/filter/network/http_connection_manager/v2/BUILD b/api/envoy/config/filter/network/http_connection_manager/v2/BUILD index 7393796c00fe7..6a090f3a115d2 100644 --- a/api/envoy/config/filter/network/http_connection_manager/v2/BUILD +++ b/api/envoy/config/filter/network/http_connection_manager/v2/BUILD @@ -21,8 +21,6 @@ api_proto_library_internal( "//envoy/api/v2/core:config_source", "//envoy/api/v2/core:protocol", "//envoy/config/filter/accesslog/v2:accesslog", - "//envoy/data/accesslog/v2:accesslog", "//envoy/type:percent", - "//envoy/type/matcher:string", ], ) diff --git a/api/envoy/config/filter/network/http_connection_manager/v2/http_connection_manager.proto b/api/envoy/config/filter/network/http_connection_manager/v2/http_connection_manager.proto index 589afc95751d8..6f65caca4b27e 100644 --- a/api/envoy/config/filter/network/http_connection_manager/v2/http_connection_manager.proto +++ b/api/envoy/config/filter/network/http_connection_manager/v2/http_connection_manager.proto @@ -11,9 +11,7 @@ import "envoy/api/v2/core/protocol.proto"; import "envoy/api/v2/rds.proto"; import "envoy/api/v2/srds.proto"; import "envoy/config/filter/accesslog/v2/accesslog.proto"; -import "envoy/data/accesslog/v2/accesslog.proto"; import "envoy/type/percent.proto"; -import "envoy/type/matcher/string.proto"; import "google/protobuf/any.proto"; import "google/protobuf/duration.proto"; @@ -456,41 +454,25 @@ message HttpConnectionManager { // `HTTP spec ` and is provided for convenience. bool merge_slashes = 33; - // Configuration of local reply send by envoy for http responses. Allows to define custom rules - // which maps response attribute returned by envoy to different one. Currently mapping of - // status code is implemented. - message SendLocalReplyConfig { - // Configuration which allows to define custom rules for matching local response. - // It works like and operator e.g: if you define status code 404 and body pattern - // then response must match both - message Match { - oneof matcher_specifier{ - // Definition of status codes to match. - google.protobuf.UInt32Value status_codes = 1; - // Definition of body pattern to match. - envoy.type.matcher.StringMatcher body_pattern = 2; - // Definition of response flags to match. - envoy.data.accesslog.v2.ResponseFlags response_flags = 3; - // Definiton of and matcher which combine all defined rules in logical AND operation - AndMatcher and_matcher = 4; - } - }; - - // Configuration which allows to define custom mapping for matched response. - message Rewrite { - // Definition of status code to which matched one will be mapped. - google.protobuf.UInt32Value status = 1; - }; - - message AndMatcher { - repeated Match matchers = 1 [(validate.rules).repeated .min_items = 2]; + // // Determines if adjacent slashes in the path are merged into one before any processing of + // // requests by HTTP filters or routing. This affects the upstream *:path* header as well. Without + // // setting this option, incoming requests with path `//dir///file` will not match against route + // // with `prefix` match set to `/dir`. Defaults to `false`. Note that slash merging is not part of + // // `HTTP spec ` and is provided for convenience. + // bool merge_slashes = 33; + + // Configuration of local reply send by envoy for http responses. + message LocalReplyConfig { + oneof format { + // Response body text format + string text_format = 1; + + // Response body json format as dictionary + google.protobuf.Struct json_format = 2; } - - repeated Match match = 1; - Rewrite rewrite = 2; }; - repeated SendLocalReplyConfig send_local_reply_config = 35; + LocalReplyConfig local_reply_config = 35; } message Rds { diff --git a/api/envoy/data/accesslog/v2/BUILD b/api/envoy/data/accesslog/v2/BUILD index 55d6fb1835f1e..22c4c45ee8479 100644 --- a/api/envoy/data/accesslog/v2/BUILD +++ b/api/envoy/data/accesslog/v2/BUILD @@ -10,7 +10,6 @@ api_proto_library_internal( name = "accesslog", srcs = ["accesslog.proto"], visibility = [ - "//envoy/config/filter/network/http_connection_manager/v2:__pkg__", "//envoy/service/accesslog/v2:__pkg__", ], deps = [ diff --git a/include/envoy/access_log/access_log.h b/include/envoy/access_log/access_log.h index 3648a6e44a679..5bb2f588a1044 100644 --- a/include/envoy/access_log/access_log.h +++ b/include/envoy/access_log/access_log.h @@ -110,7 +110,8 @@ class Formatter { virtual std::string format(const Http::HeaderMap& request_headers, const Http::HeaderMap& response_headers, const Http::HeaderMap& response_trailers, - const StreamInfo::StreamInfo& stream_info) const PURE; + const StreamInfo::StreamInfo& stream_info, + const absl::string_view& body) const PURE; }; using FormatterPtr = std::unique_ptr; @@ -134,7 +135,8 @@ class FormatterProvider { virtual std::string format(const Http::HeaderMap& request_headers, const Http::HeaderMap& response_headers, const Http::HeaderMap& response_trailers, - const StreamInfo::StreamInfo& stream_info) const PURE; + const StreamInfo::StreamInfo& stream_info, + const absl::string_view& body) const PURE; }; using FormatterProviderPtr = std::unique_ptr; diff --git a/include/envoy/http/BUILD b/include/envoy/http/BUILD index ce03a17f96242..03e518e999c54 100644 --- a/include/envoy/http/BUILD +++ b/include/envoy/http/BUILD @@ -103,3 +103,11 @@ envoy_cc_library( name = "metadata_interface", hdrs = ["metadata_interface.h"], ) + +envoy_cc_library( + name = "local_reply_interface", + hdrs = ["local_reply.h"], + deps = [ + ":header_map_interface", + ], +) diff --git a/include/envoy/http/local_reply.h b/include/envoy/http/local_reply.h new file mode 100644 index 0000000000000..74f9adfda3531 --- /dev/null +++ b/include/envoy/http/local_reply.h @@ -0,0 +1,27 @@ +#pragma once + +#include +#include "envoy/http/header_map.h" +#include "envoy/stream_info/stream_info.h" + +namespace Envoy { +namespace Http { + +class Formatter { +public: + virtual ~Formatter() = default; + + virtual const std::string format(const Http::HeaderMap* request_headers, + const Http::HeaderMap* response_headers, + const Http::HeaderMap* response_trailers, + const absl::string_view& body, + const StreamInfo::StreamInfo& stream_info) const PURE; + + virtual void insertContentHeaders(const absl::string_view& body, + Http::HeaderMap* headers) const PURE; +}; + +using FormatterPtr = std::unique_ptr; + +} // namespace Http +} // namespace Envoy diff --git a/source/common/access_log/access_log_formatter.cc b/source/common/access_log/access_log_formatter.cc index 295c544aa76ec..50923f87dddc9 100644 --- a/source/common/access_log/access_log_formatter.cc +++ b/source/common/access_log/access_log_formatter.cc @@ -103,12 +103,13 @@ FormatterImpl::FormatterImpl(const std::string& format) { std::string FormatterImpl::format(const Http::HeaderMap& request_headers, const Http::HeaderMap& response_headers, const Http::HeaderMap& response_trailers, - const StreamInfo::StreamInfo& stream_info) const { + const StreamInfo::StreamInfo& stream_info, + const absl::string_view& body) const { std::string log_line; log_line.reserve(256); for (const FormatterProviderPtr& provider : providers_) { - log_line += provider->format(request_headers, response_headers, response_trailers, stream_info); + log_line += provider->format(request_headers, response_headers, response_trailers, stream_info, body); } return log_line; @@ -124,8 +125,9 @@ JsonFormatterImpl::JsonFormatterImpl(std::unordered_map JsonFormatterImpl::toMap( const Http::HeaderMap& request_headers, const Http::HeaderMap& response_headers, - const Http::HeaderMap& response_trailers, const StreamInfo::StreamInfo& stream_info) const { + const Http::HeaderMap& response_trailers, const StreamInfo::StreamInfo& stream_info, + const absl::string_view& body) const { std::unordered_map output; for (const auto& pair : json_output_format_) { output.emplace(pair.first, pair.second->format(request_headers, response_headers, - response_trailers, stream_info)); + response_trailers, stream_info, body)); } return output; } @@ -270,6 +272,8 @@ std::vector AccessLogFormatParser::parse(const std::string formatters.emplace_back(FormatterProviderPtr{ new ResponseTrailerFormatter(main_header, alternative_header, max_length)}); + } else if (absl::StartsWith(token, "RESP_BODY")) { + formatters.emplace_back(FormatterProviderPtr{new BodyFormatter()}); } else if (absl::StartsWith(token, DYNAMIC_META_TOKEN)) { std::string filter_namespace; absl::optional max_length; @@ -495,7 +499,8 @@ StreamInfoFormatter::StreamInfoFormatter(const std::string& field_name) { std::string StreamInfoFormatter::format(const Http::HeaderMap&, const Http::HeaderMap&, const Http::HeaderMap&, - const StreamInfo::StreamInfo& stream_info) const { + const StreamInfo::StreamInfo& stream_info, + const absl::string_view&) const { return field_extractor_(stream_info); } @@ -503,10 +508,20 @@ PlainStringFormatter::PlainStringFormatter(const std::string& str) : str_(str) { std::string PlainStringFormatter::format(const Http::HeaderMap&, const Http::HeaderMap&, const Http::HeaderMap&, - const StreamInfo::StreamInfo&) const { + const StreamInfo::StreamInfo&, + const absl::string_view&) const { return str_; } +BodyFormatter::BodyFormatter(){} + +std::string BodyFormatter::format(const Http::HeaderMap&, const Http::HeaderMap&, + const Http::HeaderMap&, + const StreamInfo::StreamInfo&, + const absl::string_view& body) const { + return body.data(); +} + HeaderFormatter::HeaderFormatter(const std::string& main_header, const std::string& alternative_header, absl::optional max_length) @@ -541,7 +556,8 @@ ResponseHeaderFormatter::ResponseHeaderFormatter(const std::string& main_header, std::string ResponseHeaderFormatter::format(const Http::HeaderMap&, const Http::HeaderMap& response_headers, const Http::HeaderMap&, - const StreamInfo::StreamInfo&) const { + const StreamInfo::StreamInfo&, + const absl::string_view&) const { return HeaderFormatter::format(response_headers); } @@ -552,7 +568,8 @@ RequestHeaderFormatter::RequestHeaderFormatter(const std::string& main_header, std::string RequestHeaderFormatter::format(const Http::HeaderMap& request_headers, const Http::HeaderMap&, const Http::HeaderMap&, - const StreamInfo::StreamInfo&) const { + const StreamInfo::StreamInfo&, + const absl::string_view&) const { return HeaderFormatter::format(request_headers); } @@ -563,7 +580,8 @@ ResponseTrailerFormatter::ResponseTrailerFormatter(const std::string& main_heade std::string ResponseTrailerFormatter::format(const Http::HeaderMap&, const Http::HeaderMap&, const Http::HeaderMap& response_trailers, - const StreamInfo::StreamInfo&) const { + const StreamInfo::StreamInfo&, + const absl::string_view&) const { return HeaderFormatter::format(response_trailers); } @@ -605,7 +623,8 @@ DynamicMetadataFormatter::DynamicMetadataFormatter(const std::string& filter_nam std::string DynamicMetadataFormatter::format(const Http::HeaderMap&, const Http::HeaderMap&, const Http::HeaderMap&, - const StreamInfo::StreamInfo& stream_info) const { + const StreamInfo::StreamInfo& stream_info, + const absl::string_view&) const { return MetadataFormatter::format(stream_info.dynamicMetadata()); } @@ -613,7 +632,8 @@ StartTimeFormatter::StartTimeFormatter(const std::string& format) : date_formatt std::string StartTimeFormatter::format(const Http::HeaderMap&, const Http::HeaderMap&, const Http::HeaderMap&, - const StreamInfo::StreamInfo& stream_info) const { + const StreamInfo::StreamInfo& stream_info, + const absl::string_view&) const { if (date_formatter_.formatString().empty()) { return AccessLogDateTimeFormatter::fromTime(stream_info.startTime()); } else { diff --git a/source/common/access_log/access_log_formatter.h b/source/common/access_log/access_log_formatter.h index 103657dcb40db..6e29c7723aa2c 100644 --- a/source/common/access_log/access_log_formatter.h +++ b/source/common/access_log/access_log_formatter.h @@ -93,7 +93,8 @@ class FormatterImpl : public Formatter { std::string format(const Http::HeaderMap& request_headers, const Http::HeaderMap& response_headers, const Http::HeaderMap& response_trailers, - const StreamInfo::StreamInfo& stream_info) const override; + const StreamInfo::StreamInfo& stream_info, + const absl::string_view& body) const override; private: std::vector providers_; @@ -107,7 +108,8 @@ class JsonFormatterImpl : public Formatter { std::string format(const Http::HeaderMap& request_headers, const Http::HeaderMap& response_headers, const Http::HeaderMap& response_trailers, - const StreamInfo::StreamInfo& stream_info) const override; + const StreamInfo::StreamInfo& stream_info, + const absl::string_view& body) const override; private: std::vector providers_; @@ -115,7 +117,8 @@ class JsonFormatterImpl : public Formatter { std::unordered_map toMap(const Http::HeaderMap& request_headers, const Http::HeaderMap& response_headers, - const Http::HeaderMap& response_trailers, const StreamInfo::StreamInfo& stream_info) const; + const Http::HeaderMap& response_trailers, const StreamInfo::StreamInfo& stream_info, + const absl::string_view& body) const; }; /** @@ -128,12 +131,25 @@ class PlainStringFormatter : public FormatterProvider { // Formatter::format std::string format(const Http::HeaderMap&, const Http::HeaderMap&, const Http::HeaderMap&, - const StreamInfo::StreamInfo&) const override; + const StreamInfo::StreamInfo&, const absl::string_view&) const override; private: std::string str_; }; +/** + * Formatter for string literal. It ignores headers and stream info and returns string by which it + * was initialized. + */ +class BodyFormatter : public FormatterProvider { +public: + BodyFormatter(); + + // Formatter::format + std::string format(const Http::HeaderMap&, const Http::HeaderMap&, const Http::HeaderMap&, + const StreamInfo::StreamInfo&, const absl::string_view& body) const override; +}; + class HeaderFormatter { public: HeaderFormatter(const std::string& main_header, const std::string& alternative_header, @@ -157,7 +173,7 @@ class RequestHeaderFormatter : public FormatterProvider, HeaderFormatter { // Formatter::format std::string format(const Http::HeaderMap& request_headers, const Http::HeaderMap&, - const Http::HeaderMap&, const StreamInfo::StreamInfo&) const override; + const Http::HeaderMap&, const StreamInfo::StreamInfo&, const absl::string_view&) const override; }; /** @@ -170,7 +186,7 @@ class ResponseHeaderFormatter : public FormatterProvider, HeaderFormatter { // Formatter::format std::string format(const Http::HeaderMap&, const Http::HeaderMap& response_headers, - const Http::HeaderMap&, const StreamInfo::StreamInfo&) const override; + const Http::HeaderMap&, const StreamInfo::StreamInfo&, const absl::string_view&) const override; }; /** @@ -184,7 +200,8 @@ class ResponseTrailerFormatter : public FormatterProvider, HeaderFormatter { // Formatter::format std::string format(const Http::HeaderMap&, const Http::HeaderMap&, const Http::HeaderMap& response_trailers, - const StreamInfo::StreamInfo&) const override; + const StreamInfo::StreamInfo&, + const absl::string_view&) const override; }; /** @@ -196,7 +213,7 @@ class StreamInfoFormatter : public FormatterProvider { // Formatter::format std::string format(const Http::HeaderMap&, const Http::HeaderMap&, const Http::HeaderMap&, - const StreamInfo::StreamInfo& stream_info) const override; + const StreamInfo::StreamInfo& stream_info, const absl::string_view&) const override; using FieldExtractor = std::function; @@ -230,7 +247,7 @@ class DynamicMetadataFormatter : public FormatterProvider, MetadataFormatter { // FormatterProvider::format std::string format(const Http::HeaderMap&, const Http::HeaderMap&, const Http::HeaderMap&, - const StreamInfo::StreamInfo& stream_info) const override; + const StreamInfo::StreamInfo& stream_info, const absl::string_view&) const override; }; /** @@ -240,7 +257,7 @@ class StartTimeFormatter : public FormatterProvider { public: StartTimeFormatter(const std::string& format); std::string format(const Http::HeaderMap&, const Http::HeaderMap&, const Http::HeaderMap&, - const StreamInfo::StreamInfo&) const override; + const StreamInfo::StreamInfo&, const absl::string_view&) const override; private: const Envoy::DateFormatter date_formatter_; diff --git a/source/common/http/BUILD b/source/common/http/BUILD index 9ec53a50073ed..139b854f27c90 100644 --- a/source/common/http/BUILD +++ b/source/common/http/BUILD @@ -120,10 +120,10 @@ envoy_cc_library( hdrs = ["conn_manager_config.h"], deps = [ ":date_provider_lib", + "//include/envoy/http:local_reply_interface", "//include/envoy/config:config_provider_interface", "//include/envoy/http:filter_interface", "//include/envoy/router:rds_interface", - "//source/common/http:local_reply_lib", "//source/common/network:utility_lib", ], ) @@ -188,6 +188,7 @@ envoy_cc_library( "//source/common/runtime:uuid_util_lib", "//source/common/stream_info:stream_info_lib", "//source/common/tracing:http_tracer_lib", + "//source/common/http:local_reply_formatter_lib" ], ) @@ -240,12 +241,15 @@ envoy_cc_library( ) envoy_cc_library( - name = "local_reply_lib", - hdrs = ["local_reply.h"], + name = "local_reply_formatter_lib", + srcs = ["local_reply_formatter.cc"], + hdrs = ["local_reply_formatter.h"], deps = [ - "//source/common/common:matchers_lib", - "@envoy_api//envoy/config/filter/network/http_connection_manager/v2:http_connection_manager_cc", - "@envoy_api//envoy/service/accesslog/v2:als_cc", + ":headers_lib", + "//include/envoy/http:local_reply_interface", + "//include/envoy/access_log:access_log_interface", + "//include/envoy/stream_info:stream_info_interface", + "//source/common/access_log:access_log_formatter_lib", ], ) diff --git a/source/common/http/async_client_impl.h b/source/common/http/async_client_impl.h index ac49b97c47cf0..81ad73c56cee6 100644 --- a/source/common/http/async_client_impl.h +++ b/source/common/http/async_client_impl.h @@ -326,6 +326,11 @@ class AsyncStreamImpl : public AsyncClient::Stream, encodeHeaders(std::move(headers), end_stream); }, [this](Buffer::Instance& data, bool end_stream) -> void { encodeData(data, end_stream); }, + [](absl::string_view& body, HeaderMapPtr&& headers) -> std::string { std::cout<< body; + headers->insertContentLength().value(body.size()); + headers->insertContentType().value(Headers::get().ContentTypeValues.Json); + return std::string{}; + }, remote_closed_, code, body, grpc_status, is_head_request_); } // The async client won't pause if sending an Expect: 100-Continue so simply diff --git a/source/common/http/conn_manager_config.h b/source/common/http/conn_manager_config.h index 8f89a6e821677..bca29a6b2b241 100644 --- a/source/common/http/conn_manager_config.h +++ b/source/common/http/conn_manager_config.h @@ -5,10 +5,10 @@ #include "envoy/http/filter.h" #include "envoy/router/rds.h" #include "envoy/stats/scope.h" +#include "envoy/http/local_reply.h" #include "common/http/date_provider.h" #include "common/network/utility.h" -#include "common/http/local_reply.h" namespace Envoy { namespace Http { @@ -371,10 +371,8 @@ class ConnectionManagerConfig { */ virtual bool shouldMergeSlashes() const PURE; - /** - * @return supplies the local reply mapping configuration - */ - virtual const LocalReplyConfig* localReplyConfig() const PURE; + + virtual Http::Formatter* localReplyFormatter() const PURE; }; } // namespace Http } // namespace Envoy diff --git a/source/common/http/conn_manager_impl.cc b/source/common/http/conn_manager_impl.cc index e8bde07148986..b3ec2f34eff21 100644 --- a/source/common/http/conn_manager_impl.cc +++ b/source/common/http/conn_manager_impl.cc @@ -1310,13 +1310,20 @@ void ConnectionManagerImpl::ActiveStream::sendLocalReply( response_headers_ = std::move(headers); // TODO: Start encoding from the last decoder filter that saw the // request instead. - encodeHeaders(nullptr, *response_headers_, end_stream); + encodeHeaders(nullptr, *response_headers_, end_stream); }, [this](Buffer::Instance& data, bool end_stream) -> void { // TODO: Start encoding from the last decoder filter that saw the // request instead. encodeData(nullptr, data, end_stream, FilterIterationStartState::CanStartFromCurrent); }, + [this](absl::string_view& body_text, HeaderMapPtr&& headers) -> std::string { + std::string formatted_body = this->connection_manager_.config_.localReplyFormatter()->format( + request_headers_.get(), response_headers_.get(), response_trailers_.get(), body_text, stream_info_); + this->connection_manager_.config_.localReplyFormatter()->insertContentHeaders(formatted_body, headers.get()); + + return formatted_body; + }, state_.destroyed_, code, body, grpc_status, is_head_request); } @@ -2251,6 +2258,12 @@ void ConnectionManagerImpl::ActiveStreamEncoderFilter::responseDataTooLarge() { parent_.response_encoder_->encodeData(data, end_stream); parent_.state_.local_complete_ = end_stream; }, + [&](absl::string_view& body_text, HeaderMapPtr&& response_headers) -> std::string { + std::cout<< body_text ; + response_headers->insertContentLength().value(body_text.size()); + response_headers->insertContentType().value(Headers::get().ContentTypeValues.Json); + return std::string{}; + }, parent_.state_.destroyed_, Http::Code::InternalServerError, CodeUtility::toString(Http::Code::InternalServerError), absl::nullopt, parent_.is_head_request_); diff --git a/source/common/http/local_reply.h b/source/common/http/local_reply.h deleted file mode 100644 index 2e4f831e93a4c..0000000000000 --- a/source/common/http/local_reply.h +++ /dev/null @@ -1,137 +0,0 @@ -#pragma once - -#include -#include -#include - -#include "envoy/config/filter/network/http_connection_manager/v2/http_connection_manager.pb.validate.h" -#include "envoy/config/filter/accesslog/v2/accesslog.pb.validate.h" - -#include "common/common/matchers.h" - -namespace Envoy { -namespace Http { - static uint64_t toBitMask(const envoy::data::accesslog::v2::ResponseFlags& response_flags){ - uint64_t bit_mask = 0; - if (response_flags.failed_local_healthcheck()) { - bit_mask |= StreamInfo::ResponseFlag::FailedLocalHealthCheck; - } - - if (response_flags.no_healthy_upstream()) { - bit_mask |= StreamInfo::ResponseFlag::NoHealthyUpstream; - } - - if (response_flags.upstream_request_timeout()) { - bit_mask |= StreamInfo::ResponseFlag::UpstreamRequestTimeout; - } - - if (response_flags.local_reset()) { - bit_mask |= StreamInfo::ResponseFlag::LocalReset; - } - - if (response_flags.upstream_remote_reset()) { - bit_mask |= StreamInfo::ResponseFlag::UpstreamRemoteReset; - } - - if (response_flags.upstream_connection_failure()) { - bit_mask |= StreamInfo::ResponseFlag::UpstreamConnectionFailure; - } - - if (response_flags.upstream_connection_termination()) { - bit_mask |= StreamInfo::ResponseFlag::UpstreamConnectionTermination; - } - - if (response_flags.upstream_overflow()) { - bit_mask |= StreamInfo::ResponseFlag::UpstreamOverflow; - } - - if (response_flags.no_route_found()) { - bit_mask |= StreamInfo::ResponseFlag::NoRouteFound; - } - - if (response_flags.delay_injected()) { - bit_mask |= StreamInfo::ResponseFlag::DelayInjected; - } - - if (response_flags.fault_injected()) { - bit_mask |= StreamInfo::ResponseFlag::FaultInjected; - } - - if (response_flags.rate_limited()) { - bit_mask |= StreamInfo::ResponseFlag::RateLimited; - } - - // if (response_flags.unauthorized_details()) { - // bit_mask |= StreamInfo::ResponseFlag::UnauthorizedExternalService; - // } - - if (response_flags.rate_limit_service_error()) { - bit_mask |= StreamInfo::ResponseFlag::RateLimitServiceError; - } - - if (response_flags.downstream_connection_termination()) { - bit_mask |= StreamInfo::ResponseFlag::DownstreamConnectionTermination; - } - - if (response_flags.upstream_retry_limit_exceeded()) { - bit_mask |= StreamInfo::ResponseFlag::UpstreamRetryLimitExceeded; - } - - if (response_flags.stream_idle_timeout()) { - bit_mask |= StreamInfo::ResponseFlag::StreamIdleTimeout; - } - - if (response_flags.invalid_envoy_request_headers()) { - bit_mask |= StreamInfo::ResponseFlag::InvalidEnvoyRequestHeaders; - } - - return bit_mask; - } - -struct LocalReplyMatcher { - LocalReplyMatcher(std::vector& status_codes, - const envoy::type::matcher::StringMatcher& body_pattern, - const envoy::data::accesslog::v2::ResponseFlags& response_flags) - : status_codes_(move(status_codes)), body_pattern_(body_pattern), response_flags_(toBitMask(response_flags)){}; - - bool match(const absl::string_view value) const { - return body_pattern_.match(value); - } - - std::vector status_codes_; - Matchers::StringMatcherImpl body_pattern_; - uint64_t response_flags_; -}; - -/** - * Structure which holds rewriter configuration from proto file for LocalReplyConfig. - */ -struct LocalReplyRewriter { - uint32_t status_; -}; - -class LocalReplyConfig { -public: - LocalReplyConfig( - const envoy::config::filter::network::http_connection_manager::v2::HttpConnectionManager& - config) { - for (const auto& match_rewrite_config : config.send_local_reply_config()) { - std::vector status_codes; - for (const auto code : match_rewrite_config.match().status_codes()) { - status_codes.emplace_back(code); - } - - std::pair pair = std::make_pair( - LocalReplyMatcher{status_codes, match_rewrite_config.match().body_pattern(), match_rewrite_config.match().response_flags()}, - LocalReplyRewriter{match_rewrite_config.rewrite().status()}); - match_rewrite_pair_list_.emplace_back(std::move(pair)); - } - }; -private: - std::list> match_rewrite_pair_list_; -}; - -using LocalReplyConfigConstPtr = std::unique_ptr; - -} // namespace Http -} // namespace Envoy diff --git a/source/common/http/local_reply_formatter.cc b/source/common/http/local_reply_formatter.cc new file mode 100644 index 0000000000000..65610218452fd --- /dev/null +++ b/source/common/http/local_reply_formatter.cc @@ -0,0 +1,30 @@ +#include "common/http/local_reply_formatter.h" + +#include "envoy/http/local_reply.h" +#include "envoy/stream_info/stream_info.h" +#include "common/http/headers.h" +#include "common/access_log/access_log_formatter.h" + +namespace Envoy{ +namespace Http{ +JsonFormatterImpl::JsonFormatterImpl(std::unordered_map formatter){ + formatter_ = std::make_unique(formatter); +} + +const std::string JsonFormatterImpl::format(const Http::HeaderMap* request_headers, + const Http::HeaderMap* response_headers, + const Http::HeaderMap* response_trailers, + const absl::string_view& body, + const StreamInfo::StreamInfo& stream_info) const { + return formatter_->format(*request_headers, *response_headers, *response_trailers, stream_info, body); +} + +void JsonFormatterImpl::insertContentHeaders(const absl::string_view& body, + Http::HeaderMap* headers) const { + headers->insertContentLength().value(body.size()); + headers->insertContentType().value(Headers::get().ContentTypeValues.Json); +} + +} +} + diff --git a/source/common/http/local_reply_formatter.h b/source/common/http/local_reply_formatter.h new file mode 100644 index 0000000000000..8d0b6a7092aa3 --- /dev/null +++ b/source/common/http/local_reply_formatter.h @@ -0,0 +1,32 @@ +#pragma once + +#include + +#include "envoy/http/local_reply.h" +#include "common/access_log/access_log_formatter.h" +#include "envoy/stream_info/stream_info.h" + +namespace Envoy{ +namespace Http{ + + +class JsonFormatterImpl : public Formatter { +public: + JsonFormatterImpl(std::unordered_map formatter); + + // Formatter::format +const std::string format(const Http::HeaderMap* request_headers, + const Http::HeaderMap* response_headers, + const Http::HeaderMap* response_trailers, + const absl::string_view& body, + const StreamInfo::StreamInfo& stream_info) const override; + +void insertContentHeaders(const absl::string_view& body, + Http::HeaderMap* headers) const override; + +private: + AccessLog::FormatterPtr formatter_; +}; +} +} + diff --git a/source/common/http/utility.cc b/source/common/http/utility.cc index 11bedbeba9077..83f4a503b9e85 100644 --- a/source/common/http/utility.cc +++ b/source/common/http/utility.cc @@ -291,12 +291,19 @@ void Utility::sendLocalReply(bool is_grpc, StreamDecoderFilterCallbacks& callbac [&](Buffer::Instance& data, bool end_stream) -> void { callbacks.encodeData(data, end_stream); }, + [&](absl::string_view& body,HeaderMapPtr&& headers) -> std::string { + std::cout<< body; + headers->insertContentLength().value(body.size()); + headers->insertContentType().value(Headers::get().ContentTypeValues.Json); + return std::string{}; + }, is_reset, response_code, body_text, grpc_status, is_head_request); } void Utility::sendLocalReply( bool is_grpc, std::function encode_headers, - std::function encode_data, const bool& is_reset, + std::function encode_data, + std::function format_data, const bool& is_reset, Code response_code, absl::string_view body_text, const absl::optional grpc_status, bool is_head_request) { // encode_headers() may reset the stream, so the stream must not be reset before calling it. @@ -319,11 +326,13 @@ void Utility::sendLocalReply( return; } + + HeaderMapPtr response_headers{ new HeaderMapImpl{{Headers::get().Status, std::to_string(enumToInt(response_code))}}}; + std::string formatted_body; if (!body_text.empty()) { - response_headers->insertContentLength().value(body_text.size()); - response_headers->insertContentType().value(Headers::get().ContentTypeValues.Text); + formatted_body = format_data(body_text ,std::move(response_headers)); } if (is_head_request) { @@ -331,10 +340,10 @@ void Utility::sendLocalReply( return; } - encode_headers(std::move(response_headers), body_text.empty()); + encode_headers(std::move(response_headers), formatted_body.empty()); // encode_headers()) may have changed the referenced is_reset so we need to test it - if (!body_text.empty() && !is_reset) { - Buffer::OwnedImpl buffer(body_text); + if (!formatted_body.empty() && !is_reset) { + Buffer::OwnedImpl buffer(formatted_body); encode_data(buffer, true); } } diff --git a/source/common/http/utility.h b/source/common/http/utility.h index fef7b08e11b6d..0afded7ba5db7 100644 --- a/source/common/http/utility.h +++ b/source/common/http/utility.h @@ -209,6 +209,7 @@ void sendLocalReply(bool is_grpc, StreamDecoderFilterCallbacks& callbacks, const void sendLocalReply(bool is_grpc, std::function encode_headers, std::function encode_data, + std::function format_data, const bool& is_reset, Code response_code, absl::string_view body_text, const absl::optional grpc_status, bool is_head_request = false); diff --git a/source/common/router/header_formatter.cc b/source/common/router/header_formatter.cc index 706fd282b10b5..1a9c6cb8745bc 100644 --- a/source/common/router/header_formatter.cc +++ b/source/common/router/header_formatter.cc @@ -292,7 +292,7 @@ StreamInfoHeaderFormatter::StreamInfoHeaderFormatter(absl::string_view field_nam std::string formatted; for (const auto& formatter : formatters) { absl::StrAppend(&formatted, - formatter->format(empty_map, empty_map, empty_map, stream_info)); + formatter->format(empty_map, empty_map, empty_map, stream_info, std::string())); } return formatted; }; diff --git a/source/extensions/access_loggers/file/file_access_log_impl.cc b/source/extensions/access_loggers/file/file_access_log_impl.cc index 410204d3ad86f..0692159c8a367 100644 --- a/source/extensions/access_loggers/file/file_access_log_impl.cc +++ b/source/extensions/access_loggers/file/file_access_log_impl.cc @@ -17,7 +17,7 @@ void FileAccessLog::emitLog(const Http::HeaderMap& request_headers, const Http::HeaderMap& response_trailers, const StreamInfo::StreamInfo& stream_info) { log_file_->write( - formatter_->format(request_headers, response_headers, response_trailers, stream_info)); + formatter_->format(request_headers, response_headers, response_trailers, stream_info, std::string())); } } // namespace File diff --git a/source/extensions/filters/network/http_connection_manager/BUILD b/source/extensions/filters/network/http_connection_manager/BUILD index e297d8ed2447e..8df0f3be42351 100644 --- a/source/extensions/filters/network/http_connection_manager/BUILD +++ b/source/extensions/filters/network/http_connection_manager/BUILD @@ -31,8 +31,8 @@ envoy_cc_library( "//source/common/config:utility_lib", "//source/common/http:conn_manager_lib", "//source/common/http:default_server_string_lib", - "//source/common/http:local_reply_lib", "//source/common/http:utility_lib", + "//source/common/http:local_reply_formatter_lib", "//source/common/http/http1:codec_lib", "//source/common/http/http2:codec_lib", "//source/common/json:json_loader_lib", diff --git a/source/extensions/filters/network/http_connection_manager/config.cc b/source/extensions/filters/network/http_connection_manager/config.cc index 930d33f192333..7cadba865cd63 100644 --- a/source/extensions/filters/network/http_connection_manager/config.cc +++ b/source/extensions/filters/network/http_connection_manager/config.cc @@ -19,6 +19,7 @@ #include "common/http/default_server_string.h" #include "common/http/http1/codec_impl.h" #include "common/http/http2/codec_impl.h" +#include "common/http/local_reply_formatter.h" #include "common/http/utility.h" #include "common/json/config_schemas.h" #include "common/protobuf/utility.h" @@ -65,6 +66,43 @@ std::unique_ptr createInternalAddressConfig( return std::make_unique(); } +std::unordered_mapconvertJsonFormatToMap(ProtobufWkt::Struct json_format) { + std::unordered_map output; + for (const auto& pair : json_format.fields()) { + if (pair.second.kind_case() != ProtobufWkt::Value::kStringValue) { + throw EnvoyException("Only string values are supported in the JSON access log format."); + } + output.emplace(pair.first, pair.second.string_value()); + } + return output; +} + +std::unordered_map createLocalReplyFormatter(const envoy::config::filter::network::http_connection_manager::v2::HttpConnectionManager& config) { + // AccessLog::Formatter formatter; + + // if (config.access_log_format_case() == envoy::config::accesslog::v2::FileAccessLog::kFormat || + // fal_config.access_log_format_case() == + // envoy::config::accesslog::v2::FileAccessLog::ACCESS_LOG_FORMAT_NOT_SET) { + // if (fal_config.format().empty()) { + // formatter = AccessLog::AccessLogFormatUtils::defaultAccessLogFormatter(); + // } else { + // formatter = std::make_unique(fal_config.format()); + // } + // } else + std::unordered_map json_format_map; + if (config.local_reply_config().format_case() == + envoy::config::filter::network::http_connection_manager::v2::HttpConnectionManager::LocalReplyConfig::kJsonFormat) { + json_format_map = convertJsonFormatToMap(config.local_reply_config().json_format()); + // formatter = AccessLog::JsonFormatterImpl(json_format_map); + } else { + throw EnvoyException( + "Invalid access_log format provided. Only 'format' and 'json_format' are supported."); + } + +return json_format_map; + // return std::make_unique(formatter); +} + } // namespace // Singleton registration via macro defined in envoy/singleton/manager.h @@ -359,9 +397,8 @@ HttpConnectionManagerConfig::HttpConnectionManagerConfig( std::make_pair(name, FilterConfig{std::move(factories), enabled})); } } - if (config.send_local_reply_config().size() > 0) { - local_reply_config_ = Http::LocalReplyConfigConstPtr(new Http::LocalReplyConfig(config)); - } + + local_reply_formatter_ = std::make_unique(createLocalReplyFormatter(config)); } void HttpConnectionManagerConfig::processFilter( diff --git a/source/extensions/filters/network/http_connection_manager/config.h b/source/extensions/filters/network/http_connection_manager/config.h index 4e0b9d369fb7c..90e48731c6161 100644 --- a/source/extensions/filters/network/http_connection_manager/config.h +++ b/source/extensions/filters/network/http_connection_manager/config.h @@ -12,9 +12,9 @@ #include "envoy/http/filter.h" #include "envoy/router/route_config_provider_manager.h" +#include "common/access_log/access_log_formatter.h" #include "common/common/logger.h" #include "common/http/conn_manager_impl.h" -#include "common/http/local_reply.h" #include "common/json/json_loader.h" #include "extensions/filters/network/common/factory_base.h" @@ -143,9 +143,7 @@ class HttpConnectionManagerConfig : Logger::Loggable, const Http::Http1Settings& http1Settings() const override { return http1_settings_; } bool shouldNormalizePath() const override { return normalize_path_; } bool shouldMergeSlashes() const override { return merge_slashes_; } - const Http::LocalReplyConfig* localReplyConfig() const override { - return local_reply_config_.get(); - } + Http::Formatter* localReplyFormatter() const override { return local_reply_formatter_.get(); } std::chrono::milliseconds delayedCloseTimeout() const override { return delayed_close_timeout_; } private: @@ -193,7 +191,7 @@ class HttpConnectionManagerConfig : Logger::Loggable, std::chrono::milliseconds delayed_close_timeout_; const bool normalize_path_; const bool merge_slashes_; - Http::LocalReplyConfigConstPtr local_reply_config_; + Http::FormatterPtr local_reply_formatter_; // Default idle timeout is 5 minutes if nothing is specified in the HCM config. static const uint64_t StreamIdleTimeoutMs = 5 * 60 * 1000; diff --git a/source/extensions/filters/network/kafka/BUILD b/source/extensions/filters/network/kafka/BUILD index 92202ff7e538b..9d3418a21aaf8 100644 --- a/source/extensions/filters/network/kafka/BUILD +++ b/source/extensions/filters/network/kafka/BUILD @@ -26,7 +26,7 @@ envoy_cc_library( name = "kafka_request_codec_lib", srcs = ["request_codec.cc"], hdrs = [ - "codec.h", + "codec.h", "request_codec.h", ], deps = [ diff --git a/source/server/http/admin.h b/source/server/http/admin.h index 9d1d8bf29f217..74623c4a05ff9 100644 --- a/source/server/http/admin.h +++ b/source/server/http/admin.h @@ -147,7 +147,7 @@ class AdminImpl : public Admin, const Http::Http1Settings& http1Settings() const override { return http1_settings_; } bool shouldNormalizePath() const override { return true; } bool shouldMergeSlashes() const override { return true; } - Http::LocalReplyConfig* localReplyConfig() const override { return nullptr; } + Http::Formatter* localReplyFormatter() const override { return nullptr; } Http::Code request(absl::string_view path_and_query, absl::string_view method, Http::HeaderMap& response_headers, std::string& body) override; void closeSocket(); From 8f022b61d654b5e96f240c0008511e1954afb6eb Mon Sep 17 00:00:00 2001 From: Lukasz Dziedziak Date: Sun, 15 Sep 2019 10:02:04 +0200 Subject: [PATCH 09/20] Added mapper config Signed-off-by: Lukasz Dziedziak --- .../v2/http_connection_manager.proto | 39 +++++- bazel/foreign_cc/BUILD | 36 +---- include/envoy/http/local_reply.h | 7 + source/common/http/BUILD | 3 + source/common/http/async_client_impl.h | 1 + source/common/http/conn_manager_impl.cc | 5 + source/common/http/local_reply_formatter.cc | 125 +++++++++++++++++- source/common/http/local_reply_formatter.h | 73 +++++++++- source/common/http/utility.cc | 6 +- source/common/http/utility.h | 1 + .../network/http_connection_manager/config.cc | 6 +- 11 files changed, 264 insertions(+), 38 deletions(-) diff --git a/api/envoy/config/filter/network/http_connection_manager/v2/http_connection_manager.proto b/api/envoy/config/filter/network/http_connection_manager/v2/http_connection_manager.proto index 6f65caca4b27e..071cd9fcfc976 100644 --- a/api/envoy/config/filter/network/http_connection_manager/v2/http_connection_manager.proto +++ b/api/envoy/config/filter/network/http_connection_manager/v2/http_connection_manager.proto @@ -463,18 +463,53 @@ message HttpConnectionManager { // Configuration of local reply send by envoy for http responses. message LocalReplyConfig { + repeated ResponseMapper mapper = 1; + oneof format { // Response body text format - string text_format = 1; + string text_format = 2; // Response body json format as dictionary - google.protobuf.Struct json_format = 2; + google.protobuf.Struct json_format = 3; } }; LocalReplyConfig local_reply_config = 35; } +message ResponseMapper { + ResponseMatcher matcher = 1; + + ResponseRewriter rewriter = 2; +} + +message ResponseMatcher { + oneof matcher_specifier { + option (validate.required) = true; + + // And filter. + AndFilter and_filter = 1; + + // Or filter. + OrFilter or_filter = 2; + + // Response flag filter. + envoy.config.filter.accesslog.v2.ResponseFlagFilter response_flag_filter = 3; + } +} + +message ResponseRewriter { + google.protobuf.UInt32Value status_code = 1; +} + +message AndFilter { + repeated ResponseMatcher filters = 1 [(validate.rules).repeated .min_items = 2]; +} + +message OrFilter { + repeated ResponseMatcher filters = 1 [(validate.rules).repeated .min_items = 2]; +} + message Rds { // Configuration source specifier for RDS. envoy.api.v2.core.ConfigSource config_source = 1 [(validate.rules).message.required = true]; diff --git a/bazel/foreign_cc/BUILD b/bazel/foreign_cc/BUILD index 588673187b08d..2d342e5c87d1a 100644 --- a/bazel/foreign_cc/BUILD +++ b/bazel/foreign_cc/BUILD @@ -62,49 +62,27 @@ envoy_cmake_external( }), ) + envoy_cmake_external( name = "curl", - # Options from https://github.com/curl/curl/blob/master/CMakeLists.txt. cache_entries = { "BUILD_CURL_EXE": "off", - "BUILD_TESTING": "off", "BUILD_SHARED_LIBS": "off", + "CMAKE_BUILD_TYPE": "RelWithDebInfo", + "HTTP_ONLY": "on", + "BUILD_TESTING": "off", + "CMAKE_USE_OPENSSL": "off", + "CURL_CA_PATH": "none", "CURL_HIDDEN_SYMBOLS": "off", "CMAKE_USE_LIBSSH2": "off", - "CURL_BROTLI": "off", - "CMAKE_USE_GSSAPI": "off", - "HTTP_ONLY": "on", - "CMAKE_BUILD_TYPE": "RelWithDebInfo", "CMAKE_INSTALL_LIBDIR": "lib", - # C-Ares. - "ENABLE_ARES": "on", - "CARES_LIBRARY": "$EXT_BUILD_DEPS/ares", - "CARES_INCLUDE_DIR": "$EXT_BUILD_DEPS/ares/include", - # SSL (via Envoy's SSL dependency) is disabled, curl's CMake uses FindOpenSSL.cmake which fails at what looks like - # version parsing (the libraries are found ok). - "CURL_CA_PATH": "none", - "CMAKE_USE_OPENSSL": "off", - "OPENSSL_ROOT_DIR": "$EXT_BUILD_DEPS", - # NGHTTP2. - "USE_NGHTTP2": "on", - "NGHTTP2_LIBRARY": "$EXT_BUILD_DEPS/nghttp2", - "NGHTTP2_INCLUDE_DIR": "$EXT_BUILD_DEPS/nghttp2/include", - # ZLIB. - "CURL_ZLIB": "on", - "ZLIB_LIBRARY": "$EXT_BUILD_DEPS/zlib", - "ZLIB_INCLUDE_DIR": "$EXT_BUILD_DEPS/zlib/include", + "INCLUDE_DIRECTORIES": "include/curl", }, lib_source = "@com_github_curl//:all", static_libraries = select({ "//bazel:windows_x86_64": ["curl.lib"], "//conditions:default": ["libcurl.a"], }), - deps = [ - ":ares", - ":nghttp2", - ":zlib", - "//external:ssl", - ], ) envoy_cmake_external( diff --git a/include/envoy/http/local_reply.h b/include/envoy/http/local_reply.h index 74f9adfda3531..84ea587fb7929 100644 --- a/include/envoy/http/local_reply.h +++ b/include/envoy/http/local_reply.h @@ -2,6 +2,7 @@ #include #include "envoy/http/header_map.h" +#include "envoy/http/codes.h" #include "envoy/stream_info/stream_info.h" namespace Envoy { @@ -19,6 +20,12 @@ class Formatter { virtual void insertContentHeaders(const absl::string_view& body, Http::HeaderMap* headers) const PURE; + + virtual void rewriteMatchedResponse(const Http::HeaderMap* request_headers, + const Http::HeaderMap* response_headers, + const Http::HeaderMap* response_trailers, + const StreamInfo::StreamInfo& stream_info, + Code& response_code) const PURE; }; using FormatterPtr = std::unique_ptr; diff --git a/source/common/http/BUILD b/source/common/http/BUILD index 139b854f27c90..a301a1f2cb556 100644 --- a/source/common/http/BUILD +++ b/source/common/http/BUILD @@ -249,7 +249,10 @@ envoy_cc_library( "//include/envoy/http:local_reply_interface", "//include/envoy/access_log:access_log_interface", "//include/envoy/stream_info:stream_info_interface", + "//include/envoy/server:access_log_config_interface", "//source/common/access_log:access_log_formatter_lib", + "//source/common/access_log:access_log_lib", + "@envoy_api//envoy/config/filter/network/http_connection_manager/v2:http_connection_manager_cc", ], ) diff --git a/source/common/http/async_client_impl.h b/source/common/http/async_client_impl.h index 81ad73c56cee6..8c43a431f44ec 100644 --- a/source/common/http/async_client_impl.h +++ b/source/common/http/async_client_impl.h @@ -331,6 +331,7 @@ class AsyncStreamImpl : public AsyncClient::Stream, headers->insertContentType().value(Headers::get().ContentTypeValues.Json); return std::string{}; }, + [](Code& ) -> void { }, remote_closed_, code, body, grpc_status, is_head_request_); } // The async client won't pause if sending an Expect: 100-Continue so simply diff --git a/source/common/http/conn_manager_impl.cc b/source/common/http/conn_manager_impl.cc index b3ec2f34eff21..496863ebb8816 100644 --- a/source/common/http/conn_manager_impl.cc +++ b/source/common/http/conn_manager_impl.cc @@ -1324,6 +1324,10 @@ void ConnectionManagerImpl::ActiveStream::sendLocalReply( return formatted_body; }, + [this](Code& response_code) -> void{ + this->connection_manager_.config_.localReplyFormatter()->rewriteMatchedResponse( request_headers_.get(), + response_headers_.get(), response_trailers_.get(), stream_info_, response_code); + }, state_.destroyed_, code, body, grpc_status, is_head_request); } @@ -2264,6 +2268,7 @@ void ConnectionManagerImpl::ActiveStreamEncoderFilter::responseDataTooLarge() { response_headers->insertContentType().value(Headers::get().ContentTypeValues.Json); return std::string{}; }, + [&] (Code&) -> void {}, parent_.state_.destroyed_, Http::Code::InternalServerError, CodeUtility::toString(Http::Code::InternalServerError), absl::nullopt, parent_.is_head_request_); diff --git a/source/common/http/local_reply_formatter.cc b/source/common/http/local_reply_formatter.cc index 65610218452fd..391e344aafea2 100644 --- a/source/common/http/local_reply_formatter.cc +++ b/source/common/http/local_reply_formatter.cc @@ -1,14 +1,73 @@ #include "common/http/local_reply_formatter.h" +#include "envoy/http/codes.h" #include "envoy/http/local_reply.h" #include "envoy/stream_info/stream_info.h" +#include "envoy/runtime/runtime.h" +#include "envoy/access_log/access_log.h" +#include "envoy/server/filter_config.h" + +#include "common/protobuf/protobuf.h" #include "common/http/headers.h" #include "common/access_log/access_log_formatter.h" +#include "common/access_log/access_log_impl.h" + +#include "envoy/config/filter/network/http_connection_manager/v2/http_connection_manager.pb.validate.h" namespace Envoy{ namespace Http{ -JsonFormatterImpl::JsonFormatterImpl(std::unordered_map formatter){ +namespace { + + +AccessLog::FilterPtr fromProto(const envoy::config::filter::network::http_connection_manager::v2::ResponseMatcher& config, + Runtime::Loader& runtime, Runtime::RandomGenerator& random, + ProtobufMessage::ValidationVisitor& validation_visitor) { + switch (config.matcher_specifier_case()) { + case envoy::config::filter::network::http_connection_manager::v2::ResponseMatcher::kAndFilter: + return AccessLog::FilterPtr{new Http::AndFilter(config.and_filter(), runtime, random, validation_visitor)}; + case envoy::config::filter::network::http_connection_manager::v2::ResponseMatcher::kOrFilter: + return AccessLog::FilterPtr{new Http::OrFilter(config.or_filter(), runtime, random, validation_visitor)}; + case envoy::config::filter::network::http_connection_manager::v2::ResponseMatcher::kResponseFlagFilter: + MessageUtil::validate(config, validation_visitor); + return AccessLog::FilterPtr{new AccessLog::ResponseFlagFilter(config.response_flag_filter())}; + default: + NOT_REACHED_GCOVR_EXCL_LINE; + } +} + +std::list> createMatcherRewriter( + const envoy::config::filter::network::http_connection_manager::v2::HttpConnectionManager& config, + Server::Configuration::FactoryContext& context){ + + if(config.has_local_reply_config() && !config.local_reply_config().mapper().empty()){ + std::list> list_of_pairs; + for(auto& config_pair: config.local_reply_config().mapper()){ + if (config_pair.has_matcher() && config_pair.has_rewriter()){ + + std::pair pair = std::make_pair( + fromProto(config_pair.matcher(), context.runtime(), context.random(), context.messageValidationVisitor()), + Http::ResponseRewriter{PROTOBUF_GET_WRAPPED_OR_DEFAULT(config_pair.rewriter(), status_code, absl::optional())} + ); + + list_of_pairs.emplace_back(std::move(pair)); + } + } + return list_of_pairs; + } + + return std::list>{}; + +} +} + + //Here we need to pass list of filters and rewrite +JsonFormatterImpl::JsonFormatterImpl(std::unordered_map formatter, + const envoy::config::filter::network::http_connection_manager::v2::HttpConnectionManager& config, + Server::Configuration::FactoryContext& context) + { formatter_ = std::make_unique(formatter); + match_and_rewrite_ = createMatcherRewriter(config, context); + } const std::string JsonFormatterImpl::format(const Http::HeaderMap* request_headers, @@ -16,15 +75,79 @@ const std::string JsonFormatterImpl::format(const Http::HeaderMap* request_heade const Http::HeaderMap* response_trailers, const absl::string_view& body, const StreamInfo::StreamInfo& stream_info) const { + return formatter_->format(*request_headers, *response_headers, *response_trailers, stream_info, body); } + +void JsonFormatterImpl::rewriteMatchedResponse(const Http::HeaderMap* request_headers, + const Http::HeaderMap* response_headers, + const Http::HeaderMap* response_trailers, + const StreamInfo::StreamInfo& stream_info, + Code& response_code) const{ + for(auto& pair: match_and_rewrite_){ + if(pair.first->evaluate(stream_info, *request_headers, *response_headers, *response_trailers)){ + response_code = static_cast(pair.second.response_code_.value()); + break; + } + } +} + void JsonFormatterImpl::insertContentHeaders(const absl::string_view& body, Http::HeaderMap* headers) const { headers->insertContentLength().value(body.size()); headers->insertContentType().value(Headers::get().ContentTypeValues.Json); } + +Http::OperatorFilter::OperatorFilter(const Protobuf::RepeatedPtrField& configs, + Runtime::Loader& runtime, Runtime::RandomGenerator& random, + ProtobufMessage::ValidationVisitor& validation_visitor) { + for (const auto& config : configs) { + filters_.emplace_back(fromProto(config, runtime, random, validation_visitor)); + } +} + +Http::OrFilter::OrFilter(const envoy::config::filter::network::http_connection_manager::v2::OrFilter& config, + Runtime::Loader& runtime, Runtime::RandomGenerator& random, + ProtobufMessage::ValidationVisitor& validation_visitor) + : OperatorFilter(config.filters(), runtime, random, validation_visitor) {} + +Http::AndFilter::AndFilter(const envoy::config::filter::network::http_connection_manager::v2::AndFilter& config, + Runtime::Loader& runtime, Runtime::RandomGenerator& random, + ProtobufMessage::ValidationVisitor& validation_visitor) + : OperatorFilter(config.filters(), runtime, random, validation_visitor) {} + +bool Http::OrFilter::evaluate(const StreamInfo::StreamInfo& info, const Http::HeaderMap& request_headers, + const Http::HeaderMap& response_headers, + const Http::HeaderMap& response_trailers) { + bool result = false; + for (auto& filter : filters_) { + result |= filter->evaluate(info, request_headers, response_headers, response_trailers); + + if (result) { + break; + } + } + + return result; +} + +bool Http::AndFilter::evaluate(const StreamInfo::StreamInfo& info, const Http::HeaderMap& request_headers, + const Http::HeaderMap& response_headers, + const Http::HeaderMap& response_trailers) { + bool result = true; + for (auto& filter : filters_) { + result &= filter->evaluate(info, request_headers, response_headers, response_trailers); + + if (!result) { + break; + } + } + + return result; +} + } } diff --git a/source/common/http/local_reply_formatter.h b/source/common/http/local_reply_formatter.h index 8d0b6a7092aa3..483defc2341a3 100644 --- a/source/common/http/local_reply_formatter.h +++ b/source/common/http/local_reply_formatter.h @@ -2,17 +2,33 @@ #include +#include "envoy/http/codes.h" #include "envoy/http/local_reply.h" -#include "common/access_log/access_log_formatter.h" +#include "envoy/access_log/access_log.h" #include "envoy/stream_info/stream_info.h" +#include "envoy/runtime/runtime.h" +#include "envoy/server/filter_config.h" +#include "common/protobuf/protobuf.h" + +#include "envoy/config/filter/network/http_connection_manager/v2/http_connection_manager.pb.validate.h" + +#include "common/access_log/access_log_formatter.h" +#include "common/access_log/access_log_impl.h" + namespace Envoy{ namespace Http{ +struct ResponseRewriter { + absl::optional response_code_; +}; + class JsonFormatterImpl : public Formatter { public: - JsonFormatterImpl(std::unordered_map formatter); + JsonFormatterImpl(std::unordered_map formatter, + const envoy::config::filter::network::http_connection_manager::v2::HttpConnectionManager& config, + Server::Configuration::FactoryContext& context); // Formatter::format const std::string format(const Http::HeaderMap* request_headers, @@ -24,9 +40,62 @@ const std::string format(const Http::HeaderMap* request_headers, void insertContentHeaders(const absl::string_view& body, Http::HeaderMap* headers) const override; +void rewriteMatchedResponse(const Http::HeaderMap* request_headers, + const Http::HeaderMap* response_headers, + const Http::HeaderMap* response_trailers, + const StreamInfo::StreamInfo& stream_info, + Code& response_code) const override; + private: AccessLog::FormatterPtr formatter_; + std::list> match_and_rewrite_; +}; + + +/** + * Base operator filter, compose other filters with operation + */ +class OperatorFilter : public AccessLog::Filter { +public: + OperatorFilter(const Protobuf::RepeatedPtrField< + envoy::config::filter::network::http_connection_manager::v2::ResponseMatcher>& configs, + Runtime::Loader& runtime, Runtime::RandomGenerator& random, + ProtobufMessage::ValidationVisitor& validation_visitor); + +protected: + std::vector filters_; +}; + +/** + * *And* operator filter, apply logical *and* operation to all of the sub filters. + */ +class AndFilter : public OperatorFilter { +public: + AndFilter(const envoy::config::filter::network::http_connection_manager::v2::AndFilter& config, Runtime::Loader& runtime, + Runtime::RandomGenerator& random, + ProtobufMessage::ValidationVisitor& validation_visitor); + + // AccessLog::Filter + bool evaluate(const StreamInfo::StreamInfo& info, const Http::HeaderMap& request_headers, + const Http::HeaderMap& response_headers, + const Http::HeaderMap& response_trailers) override; +}; + +/** + * *Or* operator filter, apply logical *or* operation to all of the sub filters. + */ +class OrFilter : public OperatorFilter { +public: + OrFilter(const envoy::config::filter::network::http_connection_manager::v2::OrFilter& config, Runtime::Loader& runtime, + Runtime::RandomGenerator& random, + ProtobufMessage::ValidationVisitor& validation_visitor); + + // AccessLog::Filter + bool evaluate(const StreamInfo::StreamInfo& info, const Http::HeaderMap& request_headers, + const Http::HeaderMap& response_headers, + const Http::HeaderMap& response_trailers) override; }; + } } diff --git a/source/common/http/utility.cc b/source/common/http/utility.cc index 83f4a503b9e85..7f6e0cd72e9d7 100644 --- a/source/common/http/utility.cc +++ b/source/common/http/utility.cc @@ -297,13 +297,15 @@ void Utility::sendLocalReply(bool is_grpc, StreamDecoderFilterCallbacks& callbac headers->insertContentType().value(Headers::get().ContentTypeValues.Json); return std::string{}; }, + [&](Code&) -> void {}, is_reset, response_code, body_text, grpc_status, is_head_request); } void Utility::sendLocalReply( bool is_grpc, std::function encode_headers, std::function encode_data, - std::function format_data, const bool& is_reset, + std::function format_data, + std::function rewrite_response, const bool& is_reset, Code response_code, absl::string_view body_text, const absl::optional grpc_status, bool is_head_request) { // encode_headers() may reset the stream, so the stream must not be reset before calling it. @@ -326,7 +328,7 @@ void Utility::sendLocalReply( return; } - + rewrite_response(response_code); HeaderMapPtr response_headers{ new HeaderMapImpl{{Headers::get().Status, std::to_string(enumToInt(response_code))}}}; diff --git a/source/common/http/utility.h b/source/common/http/utility.h index 0afded7ba5db7..8cb348f01dea6 100644 --- a/source/common/http/utility.h +++ b/source/common/http/utility.h @@ -210,6 +210,7 @@ void sendLocalReply(bool is_grpc, std::function encode_headers, std::function encode_data, std::function format_data, + std::function rewrite_response, const bool& is_reset, Code response_code, absl::string_view body_text, const absl::optional grpc_status, bool is_head_request = false); diff --git a/source/extensions/filters/network/http_connection_manager/config.cc b/source/extensions/filters/network/http_connection_manager/config.cc index 3da224cf00e0b..cd6ae5d68b1bf 100644 --- a/source/extensions/filters/network/http_connection_manager/config.cc +++ b/source/extensions/filters/network/http_connection_manager/config.cc @@ -77,7 +77,8 @@ std::unordered_mapconvertJsonFormatToMap(ProtobufWkt:: return output; } -std::unordered_map createLocalReplyFormatter(const envoy::config::filter::network::http_connection_manager::v2::HttpConnectionManager& config) { +std::unordered_map createLocalReplyFormatter( + const envoy::config::filter::network::http_connection_manager::v2::HttpConnectionManager& config) { // AccessLog::Formatter formatter; // if (config.access_log_format_case() == envoy::config::accesslog::v2::FileAccessLog::kFormat || @@ -399,7 +400,8 @@ HttpConnectionManagerConfig::HttpConnectionManagerConfig( } } - local_reply_formatter_ = std::make_unique(createLocalReplyFormatter(config)); + local_reply_formatter_ = std::make_unique( + createLocalReplyFormatter(config), config, context); } void HttpConnectionManagerConfig::processFilter( From 419a59c8391b8e63a3637c6bc0dc5c9169aaa8b2 Mon Sep 17 00:00:00 2001 From: Lukasz Dziedziak Date: Wed, 18 Sep 2019 23:21:41 +0200 Subject: [PATCH 10/20] Changed to access log filter Signed-off-by: Lukasz Dziedziak --- .../v2/http_connection_manager.proto | 32 +------------------ 1 file changed, 1 insertion(+), 31 deletions(-) diff --git a/api/envoy/config/filter/network/http_connection_manager/v2/http_connection_manager.proto b/api/envoy/config/filter/network/http_connection_manager/v2/http_connection_manager.proto index 071cd9fcfc976..cc93407ab47c1 100644 --- a/api/envoy/config/filter/network/http_connection_manager/v2/http_connection_manager.proto +++ b/api/envoy/config/filter/network/http_connection_manager/v2/http_connection_manager.proto @@ -454,13 +454,6 @@ message HttpConnectionManager { // `HTTP spec ` and is provided for convenience. bool merge_slashes = 33; - // // Determines if adjacent slashes in the path are merged into one before any processing of - // // requests by HTTP filters or routing. This affects the upstream *:path* header as well. Without - // // setting this option, incoming requests with path `//dir///file` will not match against route - // // with `prefix` match set to `/dir`. Defaults to `false`. Note that slash merging is not part of - // // `HTTP spec ` and is provided for convenience. - // bool merge_slashes = 33; - // Configuration of local reply send by envoy for http responses. message LocalReplyConfig { repeated ResponseMapper mapper = 1; @@ -478,38 +471,15 @@ message HttpConnectionManager { } message ResponseMapper { - ResponseMatcher matcher = 1; + envoy.config.filter.accesslog.v2.AccessLogFilter matcher = 1; ResponseRewriter rewriter = 2; } -message ResponseMatcher { - oneof matcher_specifier { - option (validate.required) = true; - - // And filter. - AndFilter and_filter = 1; - - // Or filter. - OrFilter or_filter = 2; - - // Response flag filter. - envoy.config.filter.accesslog.v2.ResponseFlagFilter response_flag_filter = 3; - } -} - message ResponseRewriter { google.protobuf.UInt32Value status_code = 1; } -message AndFilter { - repeated ResponseMatcher filters = 1 [(validate.rules).repeated .min_items = 2]; -} - -message OrFilter { - repeated ResponseMatcher filters = 1 [(validate.rules).repeated .min_items = 2]; -} - message Rds { // Configuration source specifier for RDS. envoy.api.v2.core.ConfigSource config_source = 1 [(validate.rules).message.required = true]; From 1cce878aeca314255490a6cea27bbf4ba5e1de6e Mon Sep 17 00:00:00 2001 From: Lukasz Dziedziak Date: Thu, 19 Sep 2019 15:59:09 +0200 Subject: [PATCH 11/20] Cleanup and initial work docs Signed-off-by: Lukasz Dziedziak --- .../v2/http_connection_manager.proto | 23 ++-- bazel/foreign_cc/BUILD | 36 ++++-- .../http/http_conn_man/http_conn_man.rst | 1 + .../http/http_conn_man/local_reply.rst | 103 ++++++++++++++++++ .../observability/access_log.rst | 2 + include/envoy/access_log/access_log.h | 6 +- include/envoy/http/BUILD | 8 -- .../common/access_log/access_log_formatter.cc | 50 +++------ .../common/access_log/access_log_formatter.h | 37 ++----- source/common/http/BUILD | 18 --- source/common/http/async_client_impl.h | 6 - source/common/http/conn_manager_config.h | 4 - source/common/http/conn_manager_impl.cc | 20 +--- source/common/http/utility.cc | 23 +--- source/common/http/utility.h | 2 - source/common/router/header_formatter.cc | 2 +- .../file/file_access_log_impl.cc | 2 +- .../network/http_connection_manager/BUILD | 1 - .../network/http_connection_manager/config.cc | 42 ------- .../network/http_connection_manager/config.h | 3 - source/extensions/filters/network/kafka/BUILD | 1 - source/server/http/admin.h | 1 - 22 files changed, 187 insertions(+), 204 deletions(-) create mode 100644 docs/root/configuration/http/http_conn_man/local_reply.rst diff --git a/api/envoy/config/filter/network/http_connection_manager/v2/http_connection_manager.proto b/api/envoy/config/filter/network/http_connection_manager/v2/http_connection_manager.proto index cc93407ab47c1..60dfa42b2886d 100644 --- a/api/envoy/config/filter/network/http_connection_manager/v2/http_connection_manager.proto +++ b/api/envoy/config/filter/network/http_connection_manager/v2/http_connection_manager.proto @@ -454,30 +454,39 @@ message HttpConnectionManager { // `HTTP spec ` and is provided for convenience. bool merge_slashes = 33; - // Configuration of local reply send by envoy for http responses. message LocalReplyConfig { + // Configuration of list of mappers which allows to filter and change local response. + // Code iterate through mappers until first match of filter. repeated ResponseMapper mapper = 1; - oneof format { - // Response body text format - string text_format = 2; + // Allows to define custom format of local reply. + oneof reply_format { + // Response body plain text format. + string format = 2; - // Response body json format as dictionary + // Response body json format as dictionary. google.protobuf.Struct json_format = 3; } }; + // Configuration of local reply returned by Envoy. Allows to specify mapping and format of response. LocalReplyConfig local_reply_config = 35; } message ResponseMapper { - envoy.config.filter.accesslog.v2.AccessLogFilter matcher = 1; + // Filter is used to determine if the response should be changed. + envoy.config.filter.accesslog.v2.AccessLogFilter filter = 1 [(validate.rules).message.required = true]; - ResponseRewriter rewriter = 2; + // Rewriter defines which values in local reply should be changed. + ResponseRewriter rewriter = 2 [(validate.rules).message.required = true]; } +// Configuration of new value for matched local response. message ResponseRewriter { + // Status code for matched response. google.protobuf.UInt32Value status_code = 1; + + // TODO: add support for GRPC rewrite. } message Rds { diff --git a/bazel/foreign_cc/BUILD b/bazel/foreign_cc/BUILD index 2d342e5c87d1a..588673187b08d 100644 --- a/bazel/foreign_cc/BUILD +++ b/bazel/foreign_cc/BUILD @@ -62,27 +62,49 @@ envoy_cmake_external( }), ) - envoy_cmake_external( name = "curl", + # Options from https://github.com/curl/curl/blob/master/CMakeLists.txt. cache_entries = { "BUILD_CURL_EXE": "off", - "BUILD_SHARED_LIBS": "off", - "CMAKE_BUILD_TYPE": "RelWithDebInfo", - "HTTP_ONLY": "on", "BUILD_TESTING": "off", - "CMAKE_USE_OPENSSL": "off", - "CURL_CA_PATH": "none", + "BUILD_SHARED_LIBS": "off", "CURL_HIDDEN_SYMBOLS": "off", "CMAKE_USE_LIBSSH2": "off", + "CURL_BROTLI": "off", + "CMAKE_USE_GSSAPI": "off", + "HTTP_ONLY": "on", + "CMAKE_BUILD_TYPE": "RelWithDebInfo", "CMAKE_INSTALL_LIBDIR": "lib", - "INCLUDE_DIRECTORIES": "include/curl", + # C-Ares. + "ENABLE_ARES": "on", + "CARES_LIBRARY": "$EXT_BUILD_DEPS/ares", + "CARES_INCLUDE_DIR": "$EXT_BUILD_DEPS/ares/include", + # SSL (via Envoy's SSL dependency) is disabled, curl's CMake uses FindOpenSSL.cmake which fails at what looks like + # version parsing (the libraries are found ok). + "CURL_CA_PATH": "none", + "CMAKE_USE_OPENSSL": "off", + "OPENSSL_ROOT_DIR": "$EXT_BUILD_DEPS", + # NGHTTP2. + "USE_NGHTTP2": "on", + "NGHTTP2_LIBRARY": "$EXT_BUILD_DEPS/nghttp2", + "NGHTTP2_INCLUDE_DIR": "$EXT_BUILD_DEPS/nghttp2/include", + # ZLIB. + "CURL_ZLIB": "on", + "ZLIB_LIBRARY": "$EXT_BUILD_DEPS/zlib", + "ZLIB_INCLUDE_DIR": "$EXT_BUILD_DEPS/zlib/include", }, lib_source = "@com_github_curl//:all", static_libraries = select({ "//bazel:windows_x86_64": ["curl.lib"], "//conditions:default": ["libcurl.a"], }), + deps = [ + ":ares", + ":nghttp2", + ":zlib", + "//external:ssl", + ], ) envoy_cmake_external( diff --git a/docs/root/configuration/http/http_conn_man/http_conn_man.rst b/docs/root/configuration/http/http_conn_man/http_conn_man.rst index ff9b3857a52fb..fa32da03e9745 100644 --- a/docs/root/configuration/http/http_conn_man/http_conn_man.rst +++ b/docs/root/configuration/http/http_conn_man/http_conn_man.rst @@ -14,3 +14,4 @@ HTTP connection manager stats runtime rds + local_reply diff --git a/docs/root/configuration/http/http_conn_man/local_reply.rst b/docs/root/configuration/http/http_conn_man/local_reply.rst new file mode 100644 index 0000000000000..1ef3fe847a0aa --- /dev/null +++ b/docs/root/configuration/http/http_conn_man/local_reply.rst @@ -0,0 +1,103 @@ +.. _config_http_conn_man_local_reply: + +Local reply modification +======================== + +The :ref:`HTTP connection manager ` supports modification of local reply which is response returned by Envoy itself +rather than response from cluster. + +Features: + +* :ref:`Local reply content modification`. +* :ref:`Local reply format modification`. + +.. _config_http_conn_man_local_reply_modification: + +Local reply content modification +-------------------------------- + +There is support for modification of local replies. You can specify list of :ref:`mappers ` which contains +pairs of :ref:`filter ` and :ref:`rewriter `. Both elements in pair has to be +specified. If more than one pair is defined then first matching is used. + +Example how to change status code when local reply contains any of these response flags: + +.. code-block:: yaml + + mapper: + filter: + response_flag_filter: + flags: + - LH + - UH + rewriter: + status_code: 504 + +.. _config_http_conn_man_local_reply_format: + +Local reply format modification +------------------------------- + +Local reply format contains command operators that extract the relevant data and insert it. +They support two formats: :ref:`format strings ` and +:ref:`"format dictionaries" `. In both cases, the :ref:`command operators ` +are used to extract the relevant data, which is then inserted into the specified reply format. +Only one reply format may be specified at the time. + +.. _config_http_conn_man_local_reply_format_string: + +Format Strings +-------------- + +Format strings are plain strings, specified using the ``format`` key. They may contain +either :ref:`command operators ` or other characters interpreted as a plain string. +The access log formatter does not make any assumptions about a new line separator, so one +has to specified as part of the format string. + +.. code-block:: none + + %RESP_BODY% %RESPONSE_CODE% %RESPONSE_FLAGS% "My custom response" + +Example of custom Envoy local reply format: + +.. code-block:: none + + upstream connect error or disconnect/reset before headers. reset reason: connection failure 204 UH My custom response + + +If format isn't specified then :ref:`default format ` is used. + +.. _config_http_conn_man_local_reply_default_format: + +Default Format String +--------------------- + +If custom format string is not specified, Envoy uses the following default format: + +.. code-block:: none + + %RESP_BODY% + +Example of the default local reply format: + +.. code-block:: none + + upstream connect error or disconnect/reset before headers. reset reason: connection failure + +.. _config_http_conn_man_local_reply_dictionaries: + +Format Dictionaries +------------------- + +Format dictionaries are dictionaries that specify a structured local reply output format, +specified using the ``json_format`` key. This allows response to be returned in a structured format +such as JSON. + +More can be found in :ref:`configuration `. + +.. _config_http_conn_man_local_reply_command_operators: + +Command Operators +----------------- + +Local reply format reuse :ref:`access log operators `, so more information can be found there. diff --git a/docs/root/configuration/observability/access_log.rst b/docs/root/configuration/observability/access_log.rst index 7ec4b57f08006..9c7df9d7e10c1 100644 --- a/docs/root/configuration/observability/access_log.rst +++ b/docs/root/configuration/observability/access_log.rst @@ -91,6 +91,8 @@ Format dictionaries have the following restrictions: * The dictionary must map strings to strings (specifically, strings to command operators). Nesting is not currently supported. +.. _config_access_log_command_operators: + Command Operators ----------------- diff --git a/include/envoy/access_log/access_log.h b/include/envoy/access_log/access_log.h index 5bb2f588a1044..3648a6e44a679 100644 --- a/include/envoy/access_log/access_log.h +++ b/include/envoy/access_log/access_log.h @@ -110,8 +110,7 @@ class Formatter { virtual std::string format(const Http::HeaderMap& request_headers, const Http::HeaderMap& response_headers, const Http::HeaderMap& response_trailers, - const StreamInfo::StreamInfo& stream_info, - const absl::string_view& body) const PURE; + const StreamInfo::StreamInfo& stream_info) const PURE; }; using FormatterPtr = std::unique_ptr; @@ -135,8 +134,7 @@ class FormatterProvider { virtual std::string format(const Http::HeaderMap& request_headers, const Http::HeaderMap& response_headers, const Http::HeaderMap& response_trailers, - const StreamInfo::StreamInfo& stream_info, - const absl::string_view& body) const PURE; + const StreamInfo::StreamInfo& stream_info) const PURE; }; using FormatterProviderPtr = std::unique_ptr; diff --git a/include/envoy/http/BUILD b/include/envoy/http/BUILD index 03e518e999c54..ce03a17f96242 100644 --- a/include/envoy/http/BUILD +++ b/include/envoy/http/BUILD @@ -103,11 +103,3 @@ envoy_cc_library( name = "metadata_interface", hdrs = ["metadata_interface.h"], ) - -envoy_cc_library( - name = "local_reply_interface", - hdrs = ["local_reply.h"], - deps = [ - ":header_map_interface", - ], -) diff --git a/source/common/access_log/access_log_formatter.cc b/source/common/access_log/access_log_formatter.cc index 28131615ca224..631c9d4f9be29 100644 --- a/source/common/access_log/access_log_formatter.cc +++ b/source/common/access_log/access_log_formatter.cc @@ -103,13 +103,12 @@ FormatterImpl::FormatterImpl(const std::string& format) { std::string FormatterImpl::format(const Http::HeaderMap& request_headers, const Http::HeaderMap& response_headers, const Http::HeaderMap& response_trailers, - const StreamInfo::StreamInfo& stream_info, - const absl::string_view& body) const { + const StreamInfo::StreamInfo& stream_info) const { std::string log_line; log_line.reserve(256); for (const FormatterProviderPtr& provider : providers_) { - log_line += provider->format(request_headers, response_headers, response_trailers, stream_info, body); + log_line += provider->format(request_headers, response_headers, response_trailers, stream_info); } return log_line; @@ -125,9 +124,8 @@ JsonFormatterImpl::JsonFormatterImpl(std::unordered_map JsonFormatterImpl::toMap( const Http::HeaderMap& request_headers, const Http::HeaderMap& response_headers, - const Http::HeaderMap& response_trailers, const StreamInfo::StreamInfo& stream_info, - const absl::string_view& body) const { + const Http::HeaderMap& response_trailers, const StreamInfo::StreamInfo& stream_info) const { std::unordered_map output; for (const auto& pair : json_output_format_) { output.emplace(pair.first, pair.second->format(request_headers, response_headers, - response_trailers, stream_info, body)); + response_trailers, stream_info)); } return output; } @@ -272,8 +270,6 @@ std::vector AccessLogFormatParser::parse(const std::string formatters.emplace_back(FormatterProviderPtr{ new ResponseTrailerFormatter(main_header, alternative_header, max_length)}); - } else if (absl::StartsWith(token, "RESP_BODY")) { - formatters.emplace_back(FormatterProviderPtr{new BodyFormatter()}); } else if (absl::StartsWith(token, DYNAMIC_META_TOKEN)) { std::string filter_namespace; absl::optional max_length; @@ -508,8 +504,7 @@ StreamInfoFormatter::StreamInfoFormatter(const std::string& field_name) { std::string StreamInfoFormatter::format(const Http::HeaderMap&, const Http::HeaderMap&, const Http::HeaderMap&, - const StreamInfo::StreamInfo& stream_info, - const absl::string_view&) const { + const StreamInfo::StreamInfo& stream_info) const { return field_extractor_(stream_info); } @@ -517,20 +512,10 @@ PlainStringFormatter::PlainStringFormatter(const std::string& str) : str_(str) { std::string PlainStringFormatter::format(const Http::HeaderMap&, const Http::HeaderMap&, const Http::HeaderMap&, - const StreamInfo::StreamInfo&, - const absl::string_view&) const { + const StreamInfo::StreamInfo&) const { return str_; } -BodyFormatter::BodyFormatter(){} - -std::string BodyFormatter::format(const Http::HeaderMap&, const Http::HeaderMap&, - const Http::HeaderMap&, - const StreamInfo::StreamInfo&, - const absl::string_view& body) const { - return body.data(); -} - HeaderFormatter::HeaderFormatter(const std::string& main_header, const std::string& alternative_header, absl::optional max_length) @@ -565,8 +550,7 @@ ResponseHeaderFormatter::ResponseHeaderFormatter(const std::string& main_header, std::string ResponseHeaderFormatter::format(const Http::HeaderMap&, const Http::HeaderMap& response_headers, const Http::HeaderMap&, - const StreamInfo::StreamInfo&, - const absl::string_view&) const { + const StreamInfo::StreamInfo&) const { return HeaderFormatter::format(response_headers); } @@ -577,8 +561,7 @@ RequestHeaderFormatter::RequestHeaderFormatter(const std::string& main_header, std::string RequestHeaderFormatter::format(const Http::HeaderMap& request_headers, const Http::HeaderMap&, const Http::HeaderMap&, - const StreamInfo::StreamInfo&, - const absl::string_view&) const { + const StreamInfo::StreamInfo&) const { return HeaderFormatter::format(request_headers); } @@ -589,8 +572,7 @@ ResponseTrailerFormatter::ResponseTrailerFormatter(const std::string& main_heade std::string ResponseTrailerFormatter::format(const Http::HeaderMap&, const Http::HeaderMap&, const Http::HeaderMap& response_trailers, - const StreamInfo::StreamInfo&, - const absl::string_view&) const { + const StreamInfo::StreamInfo&) const { return HeaderFormatter::format(response_trailers); } @@ -632,8 +614,7 @@ DynamicMetadataFormatter::DynamicMetadataFormatter(const std::string& filter_nam std::string DynamicMetadataFormatter::format(const Http::HeaderMap&, const Http::HeaderMap&, const Http::HeaderMap&, - const StreamInfo::StreamInfo& stream_info, - const absl::string_view&) const { + const StreamInfo::StreamInfo& stream_info) const { return MetadataFormatter::format(stream_info.dynamicMetadata()); } @@ -641,8 +622,7 @@ StartTimeFormatter::StartTimeFormatter(const std::string& format) : date_formatt std::string StartTimeFormatter::format(const Http::HeaderMap&, const Http::HeaderMap&, const Http::HeaderMap&, - const StreamInfo::StreamInfo& stream_info, - const absl::string_view&) const { + const StreamInfo::StreamInfo& stream_info) const { if (date_formatter_.formatString().empty()) { return AccessLogDateTimeFormatter::fromTime(stream_info.startTime()); } else { diff --git a/source/common/access_log/access_log_formatter.h b/source/common/access_log/access_log_formatter.h index 6e29c7723aa2c..103657dcb40db 100644 --- a/source/common/access_log/access_log_formatter.h +++ b/source/common/access_log/access_log_formatter.h @@ -93,8 +93,7 @@ class FormatterImpl : public Formatter { std::string format(const Http::HeaderMap& request_headers, const Http::HeaderMap& response_headers, const Http::HeaderMap& response_trailers, - const StreamInfo::StreamInfo& stream_info, - const absl::string_view& body) const override; + const StreamInfo::StreamInfo& stream_info) const override; private: std::vector providers_; @@ -108,8 +107,7 @@ class JsonFormatterImpl : public Formatter { std::string format(const Http::HeaderMap& request_headers, const Http::HeaderMap& response_headers, const Http::HeaderMap& response_trailers, - const StreamInfo::StreamInfo& stream_info, - const absl::string_view& body) const override; + const StreamInfo::StreamInfo& stream_info) const override; private: std::vector providers_; @@ -117,8 +115,7 @@ class JsonFormatterImpl : public Formatter { std::unordered_map toMap(const Http::HeaderMap& request_headers, const Http::HeaderMap& response_headers, - const Http::HeaderMap& response_trailers, const StreamInfo::StreamInfo& stream_info, - const absl::string_view& body) const; + const Http::HeaderMap& response_trailers, const StreamInfo::StreamInfo& stream_info) const; }; /** @@ -131,25 +128,12 @@ class PlainStringFormatter : public FormatterProvider { // Formatter::format std::string format(const Http::HeaderMap&, const Http::HeaderMap&, const Http::HeaderMap&, - const StreamInfo::StreamInfo&, const absl::string_view&) const override; + const StreamInfo::StreamInfo&) const override; private: std::string str_; }; -/** - * Formatter for string literal. It ignores headers and stream info and returns string by which it - * was initialized. - */ -class BodyFormatter : public FormatterProvider { -public: - BodyFormatter(); - - // Formatter::format - std::string format(const Http::HeaderMap&, const Http::HeaderMap&, const Http::HeaderMap&, - const StreamInfo::StreamInfo&, const absl::string_view& body) const override; -}; - class HeaderFormatter { public: HeaderFormatter(const std::string& main_header, const std::string& alternative_header, @@ -173,7 +157,7 @@ class RequestHeaderFormatter : public FormatterProvider, HeaderFormatter { // Formatter::format std::string format(const Http::HeaderMap& request_headers, const Http::HeaderMap&, - const Http::HeaderMap&, const StreamInfo::StreamInfo&, const absl::string_view&) const override; + const Http::HeaderMap&, const StreamInfo::StreamInfo&) const override; }; /** @@ -186,7 +170,7 @@ class ResponseHeaderFormatter : public FormatterProvider, HeaderFormatter { // Formatter::format std::string format(const Http::HeaderMap&, const Http::HeaderMap& response_headers, - const Http::HeaderMap&, const StreamInfo::StreamInfo&, const absl::string_view&) const override; + const Http::HeaderMap&, const StreamInfo::StreamInfo&) const override; }; /** @@ -200,8 +184,7 @@ class ResponseTrailerFormatter : public FormatterProvider, HeaderFormatter { // Formatter::format std::string format(const Http::HeaderMap&, const Http::HeaderMap&, const Http::HeaderMap& response_trailers, - const StreamInfo::StreamInfo&, - const absl::string_view&) const override; + const StreamInfo::StreamInfo&) const override; }; /** @@ -213,7 +196,7 @@ class StreamInfoFormatter : public FormatterProvider { // Formatter::format std::string format(const Http::HeaderMap&, const Http::HeaderMap&, const Http::HeaderMap&, - const StreamInfo::StreamInfo& stream_info, const absl::string_view&) const override; + const StreamInfo::StreamInfo& stream_info) const override; using FieldExtractor = std::function; @@ -247,7 +230,7 @@ class DynamicMetadataFormatter : public FormatterProvider, MetadataFormatter { // FormatterProvider::format std::string format(const Http::HeaderMap&, const Http::HeaderMap&, const Http::HeaderMap&, - const StreamInfo::StreamInfo& stream_info, const absl::string_view&) const override; + const StreamInfo::StreamInfo& stream_info) const override; }; /** @@ -257,7 +240,7 @@ class StartTimeFormatter : public FormatterProvider { public: StartTimeFormatter(const std::string& format); std::string format(const Http::HeaderMap&, const Http::HeaderMap&, const Http::HeaderMap&, - const StreamInfo::StreamInfo&, const absl::string_view&) const override; + const StreamInfo::StreamInfo&) const override; private: const Envoy::DateFormatter date_formatter_; diff --git a/source/common/http/BUILD b/source/common/http/BUILD index a7f21504ab14c..04c882059daa5 100644 --- a/source/common/http/BUILD +++ b/source/common/http/BUILD @@ -120,7 +120,6 @@ envoy_cc_library( hdrs = ["conn_manager_config.h"], deps = [ ":date_provider_lib", - "//include/envoy/http:local_reply_interface", "//include/envoy/config:config_provider_interface", "//include/envoy/http:filter_interface", "//include/envoy/router:rds_interface", @@ -189,7 +188,6 @@ envoy_cc_library( "//source/common/runtime:uuid_util_lib", "//source/common/stream_info:stream_info_lib", "//source/common/tracing:http_tracer_lib", - "//source/common/http:local_reply_formatter_lib" ], ) @@ -241,22 +239,6 @@ envoy_cc_library( ], ) -envoy_cc_library( - name = "local_reply_formatter_lib", - srcs = ["local_reply_formatter.cc"], - hdrs = ["local_reply_formatter.h"], - deps = [ - ":headers_lib", - "//include/envoy/http:local_reply_interface", - "//include/envoy/access_log:access_log_interface", - "//include/envoy/stream_info:stream_info_interface", - "//include/envoy/server:access_log_config_interface", - "//source/common/access_log:access_log_formatter_lib", - "//source/common/access_log:access_log_lib", - "@envoy_api//envoy/config/filter/network/http_connection_manager/v2:http_connection_manager_cc", - ], -) - envoy_cc_library( name = "message_lib", srcs = ["message_impl.cc"], diff --git a/source/common/http/async_client_impl.h b/source/common/http/async_client_impl.h index 5f72dc944960c..f00f89fa28d63 100644 --- a/source/common/http/async_client_impl.h +++ b/source/common/http/async_client_impl.h @@ -330,12 +330,6 @@ class AsyncStreamImpl : public AsyncClient::Stream, encodeHeaders(std::move(headers), end_stream); }, [this](Buffer::Instance& data, bool end_stream) -> void { encodeData(data, end_stream); }, - [](absl::string_view& body, HeaderMapPtr&& headers) -> std::string { std::cout<< body; - headers->insertContentLength().value(body.size()); - headers->insertContentType().value(Headers::get().ContentTypeValues.Json); - return std::string{}; - }, - [](Code& ) -> void { }, remote_closed_, code, body, grpc_status, is_head_request_); } // The async client won't pause if sending an Expect: 100-Continue so simply diff --git a/source/common/http/conn_manager_config.h b/source/common/http/conn_manager_config.h index bca29a6b2b241..ce4682de2a157 100644 --- a/source/common/http/conn_manager_config.h +++ b/source/common/http/conn_manager_config.h @@ -5,7 +5,6 @@ #include "envoy/http/filter.h" #include "envoy/router/rds.h" #include "envoy/stats/scope.h" -#include "envoy/http/local_reply.h" #include "common/http/date_provider.h" #include "common/network/utility.h" @@ -370,9 +369,6 @@ class ConnectionManagerConfig { * one. */ virtual bool shouldMergeSlashes() const PURE; - - - virtual Http::Formatter* localReplyFormatter() const PURE; }; } // namespace Http } // namespace Envoy diff --git a/source/common/http/conn_manager_impl.cc b/source/common/http/conn_manager_impl.cc index 9032f302edf83..8fb6149151e6f 100644 --- a/source/common/http/conn_manager_impl.cc +++ b/source/common/http/conn_manager_impl.cc @@ -1305,24 +1305,13 @@ void ConnectionManagerImpl::ActiveStream::sendLocalReply( response_headers_ = std::move(headers); // TODO: Start encoding from the last decoder filter that saw the // request instead. - encodeHeaders(nullptr, *response_headers_, end_stream); + encodeHeaders(nullptr, *response_headers_, end_stream); }, [this](Buffer::Instance& data, bool end_stream) -> void { // TODO: Start encoding from the last decoder filter that saw the // request instead. encodeData(nullptr, data, end_stream, FilterIterationStartState::CanStartFromCurrent); }, - [this](absl::string_view& body_text, HeaderMapPtr&& headers) -> std::string { - std::string formatted_body = this->connection_manager_.config_.localReplyFormatter()->format( - request_headers_.get(), response_headers_.get(), response_trailers_.get(), body_text, stream_info_); - this->connection_manager_.config_.localReplyFormatter()->insertContentHeaders(formatted_body, headers.get()); - - return formatted_body; - }, - [this](Code& response_code) -> void{ - this->connection_manager_.config_.localReplyFormatter()->rewriteMatchedResponse( request_headers_.get(), - response_headers_.get(), response_trailers_.get(), stream_info_, response_code); - }, state_.destroyed_, code, body, grpc_status, is_head_request); } @@ -2257,13 +2246,6 @@ void ConnectionManagerImpl::ActiveStreamEncoderFilter::responseDataTooLarge() { parent_.response_encoder_->encodeData(data, end_stream); parent_.state_.local_complete_ = end_stream; }, - [&](absl::string_view& body_text, HeaderMapPtr&& response_headers) -> std::string { - std::cout<< body_text ; - response_headers->insertContentLength().value(body_text.size()); - response_headers->insertContentType().value(Headers::get().ContentTypeValues.Json); - return std::string{}; - }, - [&] (Code&) -> void {}, parent_.state_.destroyed_, Http::Code::InternalServerError, CodeUtility::toString(Http::Code::InternalServerError), absl::nullopt, parent_.is_head_request_); diff --git a/source/common/http/utility.cc b/source/common/http/utility.cc index 7f6e0cd72e9d7..11bedbeba9077 100644 --- a/source/common/http/utility.cc +++ b/source/common/http/utility.cc @@ -291,21 +291,12 @@ void Utility::sendLocalReply(bool is_grpc, StreamDecoderFilterCallbacks& callbac [&](Buffer::Instance& data, bool end_stream) -> void { callbacks.encodeData(data, end_stream); }, - [&](absl::string_view& body,HeaderMapPtr&& headers) -> std::string { - std::cout<< body; - headers->insertContentLength().value(body.size()); - headers->insertContentType().value(Headers::get().ContentTypeValues.Json); - return std::string{}; - }, - [&](Code&) -> void {}, is_reset, response_code, body_text, grpc_status, is_head_request); } void Utility::sendLocalReply( bool is_grpc, std::function encode_headers, - std::function encode_data, - std::function format_data, - std::function rewrite_response, const bool& is_reset, + std::function encode_data, const bool& is_reset, Code response_code, absl::string_view body_text, const absl::optional grpc_status, bool is_head_request) { // encode_headers() may reset the stream, so the stream must not be reset before calling it. @@ -328,13 +319,11 @@ void Utility::sendLocalReply( return; } - rewrite_response(response_code); - HeaderMapPtr response_headers{ new HeaderMapImpl{{Headers::get().Status, std::to_string(enumToInt(response_code))}}}; - std::string formatted_body; if (!body_text.empty()) { - formatted_body = format_data(body_text ,std::move(response_headers)); + response_headers->insertContentLength().value(body_text.size()); + response_headers->insertContentType().value(Headers::get().ContentTypeValues.Text); } if (is_head_request) { @@ -342,10 +331,10 @@ void Utility::sendLocalReply( return; } - encode_headers(std::move(response_headers), formatted_body.empty()); + encode_headers(std::move(response_headers), body_text.empty()); // encode_headers()) may have changed the referenced is_reset so we need to test it - if (!formatted_body.empty() && !is_reset) { - Buffer::OwnedImpl buffer(formatted_body); + if (!body_text.empty() && !is_reset) { + Buffer::OwnedImpl buffer(body_text); encode_data(buffer, true); } } diff --git a/source/common/http/utility.h b/source/common/http/utility.h index 8cb348f01dea6..fef7b08e11b6d 100644 --- a/source/common/http/utility.h +++ b/source/common/http/utility.h @@ -209,8 +209,6 @@ void sendLocalReply(bool is_grpc, StreamDecoderFilterCallbacks& callbacks, const void sendLocalReply(bool is_grpc, std::function encode_headers, std::function encode_data, - std::function format_data, - std::function rewrite_response, const bool& is_reset, Code response_code, absl::string_view body_text, const absl::optional grpc_status, bool is_head_request = false); diff --git a/source/common/router/header_formatter.cc b/source/common/router/header_formatter.cc index 1a9c6cb8745bc..706fd282b10b5 100644 --- a/source/common/router/header_formatter.cc +++ b/source/common/router/header_formatter.cc @@ -292,7 +292,7 @@ StreamInfoHeaderFormatter::StreamInfoHeaderFormatter(absl::string_view field_nam std::string formatted; for (const auto& formatter : formatters) { absl::StrAppend(&formatted, - formatter->format(empty_map, empty_map, empty_map, stream_info, std::string())); + formatter->format(empty_map, empty_map, empty_map, stream_info)); } return formatted; }; diff --git a/source/extensions/access_loggers/file/file_access_log_impl.cc b/source/extensions/access_loggers/file/file_access_log_impl.cc index 0692159c8a367..410204d3ad86f 100644 --- a/source/extensions/access_loggers/file/file_access_log_impl.cc +++ b/source/extensions/access_loggers/file/file_access_log_impl.cc @@ -17,7 +17,7 @@ void FileAccessLog::emitLog(const Http::HeaderMap& request_headers, const Http::HeaderMap& response_trailers, const StreamInfo::StreamInfo& stream_info) { log_file_->write( - formatter_->format(request_headers, response_headers, response_trailers, stream_info, std::string())); + formatter_->format(request_headers, response_headers, response_trailers, stream_info)); } } // namespace File diff --git a/source/extensions/filters/network/http_connection_manager/BUILD b/source/extensions/filters/network/http_connection_manager/BUILD index 8df0f3be42351..fbe72b257b158 100644 --- a/source/extensions/filters/network/http_connection_manager/BUILD +++ b/source/extensions/filters/network/http_connection_manager/BUILD @@ -32,7 +32,6 @@ envoy_cc_library( "//source/common/http:conn_manager_lib", "//source/common/http:default_server_string_lib", "//source/common/http:utility_lib", - "//source/common/http:local_reply_formatter_lib", "//source/common/http/http1:codec_lib", "//source/common/http/http2:codec_lib", "//source/common/json:json_loader_lib", diff --git a/source/extensions/filters/network/http_connection_manager/config.cc b/source/extensions/filters/network/http_connection_manager/config.cc index cd6ae5d68b1bf..998dce6709ab3 100644 --- a/source/extensions/filters/network/http_connection_manager/config.cc +++ b/source/extensions/filters/network/http_connection_manager/config.cc @@ -19,7 +19,6 @@ #include "common/http/default_server_string.h" #include "common/http/http1/codec_impl.h" #include "common/http/http2/codec_impl.h" -#include "common/http/local_reply_formatter.h" #include "common/http/utility.h" #include "common/json/config_schemas.h" #include "common/protobuf/utility.h" @@ -66,44 +65,6 @@ std::unique_ptr createInternalAddressConfig( return std::make_unique(); } -std::unordered_mapconvertJsonFormatToMap(ProtobufWkt::Struct json_format) { - std::unordered_map output; - for (const auto& pair : json_format.fields()) { - if (pair.second.kind_case() != ProtobufWkt::Value::kStringValue) { - throw EnvoyException("Only string values are supported in the JSON access log format."); - } - output.emplace(pair.first, pair.second.string_value()); - } - return output; -} - -std::unordered_map createLocalReplyFormatter( - const envoy::config::filter::network::http_connection_manager::v2::HttpConnectionManager& config) { - // AccessLog::Formatter formatter; - - // if (config.access_log_format_case() == envoy::config::accesslog::v2::FileAccessLog::kFormat || - // fal_config.access_log_format_case() == - // envoy::config::accesslog::v2::FileAccessLog::ACCESS_LOG_FORMAT_NOT_SET) { - // if (fal_config.format().empty()) { - // formatter = AccessLog::AccessLogFormatUtils::defaultAccessLogFormatter(); - // } else { - // formatter = std::make_unique(fal_config.format()); - // } - // } else - std::unordered_map json_format_map; - if (config.local_reply_config().format_case() == - envoy::config::filter::network::http_connection_manager::v2::HttpConnectionManager::LocalReplyConfig::kJsonFormat) { - json_format_map = convertJsonFormatToMap(config.local_reply_config().json_format()); - // formatter = AccessLog::JsonFormatterImpl(json_format_map); - } else { - throw EnvoyException( - "Invalid access_log format provided. Only 'format' and 'json_format' are supported."); - } - -return json_format_map; - // return std::make_unique(formatter); -} - } // namespace // Singleton registration via macro defined in envoy/singleton/manager.h @@ -399,9 +360,6 @@ HttpConnectionManagerConfig::HttpConnectionManagerConfig( std::make_pair(name, FilterConfig{std::move(factories), enabled})); } } - - local_reply_formatter_ = std::make_unique( - createLocalReplyFormatter(config), config, context); } void HttpConnectionManagerConfig::processFilter( diff --git a/source/extensions/filters/network/http_connection_manager/config.h b/source/extensions/filters/network/http_connection_manager/config.h index 90e48731c6161..0385762236c1d 100644 --- a/source/extensions/filters/network/http_connection_manager/config.h +++ b/source/extensions/filters/network/http_connection_manager/config.h @@ -12,7 +12,6 @@ #include "envoy/http/filter.h" #include "envoy/router/route_config_provider_manager.h" -#include "common/access_log/access_log_formatter.h" #include "common/common/logger.h" #include "common/http/conn_manager_impl.h" #include "common/json/json_loader.h" @@ -143,7 +142,6 @@ class HttpConnectionManagerConfig : Logger::Loggable, const Http::Http1Settings& http1Settings() const override { return http1_settings_; } bool shouldNormalizePath() const override { return normalize_path_; } bool shouldMergeSlashes() const override { return merge_slashes_; } - Http::Formatter* localReplyFormatter() const override { return local_reply_formatter_.get(); } std::chrono::milliseconds delayedCloseTimeout() const override { return delayed_close_timeout_; } private: @@ -191,7 +189,6 @@ class HttpConnectionManagerConfig : Logger::Loggable, std::chrono::milliseconds delayed_close_timeout_; const bool normalize_path_; const bool merge_slashes_; - Http::FormatterPtr local_reply_formatter_; // Default idle timeout is 5 minutes if nothing is specified in the HCM config. static const uint64_t StreamIdleTimeoutMs = 5 * 60 * 1000; diff --git a/source/extensions/filters/network/kafka/BUILD b/source/extensions/filters/network/kafka/BUILD index 9d3418a21aaf8..8ff831a0274cb 100644 --- a/source/extensions/filters/network/kafka/BUILD +++ b/source/extensions/filters/network/kafka/BUILD @@ -26,7 +26,6 @@ envoy_cc_library( name = "kafka_request_codec_lib", srcs = ["request_codec.cc"], hdrs = [ - "codec.h", "request_codec.h", ], deps = [ diff --git a/source/server/http/admin.h b/source/server/http/admin.h index 74623c4a05ff9..f54d72fee7ff3 100644 --- a/source/server/http/admin.h +++ b/source/server/http/admin.h @@ -147,7 +147,6 @@ class AdminImpl : public Admin, const Http::Http1Settings& http1Settings() const override { return http1_settings_; } bool shouldNormalizePath() const override { return true; } bool shouldMergeSlashes() const override { return true; } - Http::Formatter* localReplyFormatter() const override { return nullptr; } Http::Code request(absl::string_view path_and_query, absl::string_view method, Http::HeaderMap& response_headers, std::string& body) override; void closeSocket(); From 1efc2e324c1c072c10f747bd885938c9758d30b7 Mon Sep 17 00:00:00 2001 From: Lukasz Dziedziak Date: Thu, 19 Sep 2019 16:04:27 +0200 Subject: [PATCH 12/20] Cleanup and initial work docs Signed-off-by: Lukasz Dziedziak --- include/envoy/http/local_reply.h | 34 ----- source/common/http/local_reply_formatter.cc | 153 -------------------- source/common/http/local_reply_formatter.h | 101 ------------- 3 files changed, 288 deletions(-) delete mode 100644 include/envoy/http/local_reply.h delete mode 100644 source/common/http/local_reply_formatter.cc delete mode 100644 source/common/http/local_reply_formatter.h diff --git a/include/envoy/http/local_reply.h b/include/envoy/http/local_reply.h deleted file mode 100644 index 84ea587fb7929..0000000000000 --- a/include/envoy/http/local_reply.h +++ /dev/null @@ -1,34 +0,0 @@ -#pragma once - -#include -#include "envoy/http/header_map.h" -#include "envoy/http/codes.h" -#include "envoy/stream_info/stream_info.h" - -namespace Envoy { -namespace Http { - -class Formatter { -public: - virtual ~Formatter() = default; - - virtual const std::string format(const Http::HeaderMap* request_headers, - const Http::HeaderMap* response_headers, - const Http::HeaderMap* response_trailers, - const absl::string_view& body, - const StreamInfo::StreamInfo& stream_info) const PURE; - - virtual void insertContentHeaders(const absl::string_view& body, - Http::HeaderMap* headers) const PURE; - - virtual void rewriteMatchedResponse(const Http::HeaderMap* request_headers, - const Http::HeaderMap* response_headers, - const Http::HeaderMap* response_trailers, - const StreamInfo::StreamInfo& stream_info, - Code& response_code) const PURE; -}; - -using FormatterPtr = std::unique_ptr; - -} // namespace Http -} // namespace Envoy diff --git a/source/common/http/local_reply_formatter.cc b/source/common/http/local_reply_formatter.cc deleted file mode 100644 index 391e344aafea2..0000000000000 --- a/source/common/http/local_reply_formatter.cc +++ /dev/null @@ -1,153 +0,0 @@ -#include "common/http/local_reply_formatter.h" - -#include "envoy/http/codes.h" -#include "envoy/http/local_reply.h" -#include "envoy/stream_info/stream_info.h" -#include "envoy/runtime/runtime.h" -#include "envoy/access_log/access_log.h" -#include "envoy/server/filter_config.h" - -#include "common/protobuf/protobuf.h" -#include "common/http/headers.h" -#include "common/access_log/access_log_formatter.h" -#include "common/access_log/access_log_impl.h" - -#include "envoy/config/filter/network/http_connection_manager/v2/http_connection_manager.pb.validate.h" - -namespace Envoy{ -namespace Http{ -namespace { - - -AccessLog::FilterPtr fromProto(const envoy::config::filter::network::http_connection_manager::v2::ResponseMatcher& config, - Runtime::Loader& runtime, Runtime::RandomGenerator& random, - ProtobufMessage::ValidationVisitor& validation_visitor) { - switch (config.matcher_specifier_case()) { - case envoy::config::filter::network::http_connection_manager::v2::ResponseMatcher::kAndFilter: - return AccessLog::FilterPtr{new Http::AndFilter(config.and_filter(), runtime, random, validation_visitor)}; - case envoy::config::filter::network::http_connection_manager::v2::ResponseMatcher::kOrFilter: - return AccessLog::FilterPtr{new Http::OrFilter(config.or_filter(), runtime, random, validation_visitor)}; - case envoy::config::filter::network::http_connection_manager::v2::ResponseMatcher::kResponseFlagFilter: - MessageUtil::validate(config, validation_visitor); - return AccessLog::FilterPtr{new AccessLog::ResponseFlagFilter(config.response_flag_filter())}; - default: - NOT_REACHED_GCOVR_EXCL_LINE; - } -} - -std::list> createMatcherRewriter( - const envoy::config::filter::network::http_connection_manager::v2::HttpConnectionManager& config, - Server::Configuration::FactoryContext& context){ - - if(config.has_local_reply_config() && !config.local_reply_config().mapper().empty()){ - std::list> list_of_pairs; - for(auto& config_pair: config.local_reply_config().mapper()){ - if (config_pair.has_matcher() && config_pair.has_rewriter()){ - - std::pair pair = std::make_pair( - fromProto(config_pair.matcher(), context.runtime(), context.random(), context.messageValidationVisitor()), - Http::ResponseRewriter{PROTOBUF_GET_WRAPPED_OR_DEFAULT(config_pair.rewriter(), status_code, absl::optional())} - ); - - list_of_pairs.emplace_back(std::move(pair)); - } - } - return list_of_pairs; - } - - return std::list>{}; - -} -} - - //Here we need to pass list of filters and rewrite -JsonFormatterImpl::JsonFormatterImpl(std::unordered_map formatter, - const envoy::config::filter::network::http_connection_manager::v2::HttpConnectionManager& config, - Server::Configuration::FactoryContext& context) - { - formatter_ = std::make_unique(formatter); - match_and_rewrite_ = createMatcherRewriter(config, context); - -} - -const std::string JsonFormatterImpl::format(const Http::HeaderMap* request_headers, - const Http::HeaderMap* response_headers, - const Http::HeaderMap* response_trailers, - const absl::string_view& body, - const StreamInfo::StreamInfo& stream_info) const { - - return formatter_->format(*request_headers, *response_headers, *response_trailers, stream_info, body); -} - - -void JsonFormatterImpl::rewriteMatchedResponse(const Http::HeaderMap* request_headers, - const Http::HeaderMap* response_headers, - const Http::HeaderMap* response_trailers, - const StreamInfo::StreamInfo& stream_info, - Code& response_code) const{ - for(auto& pair: match_and_rewrite_){ - if(pair.first->evaluate(stream_info, *request_headers, *response_headers, *response_trailers)){ - response_code = static_cast(pair.second.response_code_.value()); - break; - } - } -} - -void JsonFormatterImpl::insertContentHeaders(const absl::string_view& body, - Http::HeaderMap* headers) const { - headers->insertContentLength().value(body.size()); - headers->insertContentType().value(Headers::get().ContentTypeValues.Json); -} - - -Http::OperatorFilter::OperatorFilter(const Protobuf::RepeatedPtrField& configs, - Runtime::Loader& runtime, Runtime::RandomGenerator& random, - ProtobufMessage::ValidationVisitor& validation_visitor) { - for (const auto& config : configs) { - filters_.emplace_back(fromProto(config, runtime, random, validation_visitor)); - } -} - -Http::OrFilter::OrFilter(const envoy::config::filter::network::http_connection_manager::v2::OrFilter& config, - Runtime::Loader& runtime, Runtime::RandomGenerator& random, - ProtobufMessage::ValidationVisitor& validation_visitor) - : OperatorFilter(config.filters(), runtime, random, validation_visitor) {} - -Http::AndFilter::AndFilter(const envoy::config::filter::network::http_connection_manager::v2::AndFilter& config, - Runtime::Loader& runtime, Runtime::RandomGenerator& random, - ProtobufMessage::ValidationVisitor& validation_visitor) - : OperatorFilter(config.filters(), runtime, random, validation_visitor) {} - -bool Http::OrFilter::evaluate(const StreamInfo::StreamInfo& info, const Http::HeaderMap& request_headers, - const Http::HeaderMap& response_headers, - const Http::HeaderMap& response_trailers) { - bool result = false; - for (auto& filter : filters_) { - result |= filter->evaluate(info, request_headers, response_headers, response_trailers); - - if (result) { - break; - } - } - - return result; -} - -bool Http::AndFilter::evaluate(const StreamInfo::StreamInfo& info, const Http::HeaderMap& request_headers, - const Http::HeaderMap& response_headers, - const Http::HeaderMap& response_trailers) { - bool result = true; - for (auto& filter : filters_) { - result &= filter->evaluate(info, request_headers, response_headers, response_trailers); - - if (!result) { - break; - } - } - - return result; -} - -} -} - diff --git a/source/common/http/local_reply_formatter.h b/source/common/http/local_reply_formatter.h deleted file mode 100644 index 483defc2341a3..0000000000000 --- a/source/common/http/local_reply_formatter.h +++ /dev/null @@ -1,101 +0,0 @@ -#pragma once - -#include - -#include "envoy/http/codes.h" -#include "envoy/http/local_reply.h" -#include "envoy/access_log/access_log.h" -#include "envoy/stream_info/stream_info.h" -#include "envoy/runtime/runtime.h" -#include "envoy/server/filter_config.h" -#include "common/protobuf/protobuf.h" - -#include "envoy/config/filter/network/http_connection_manager/v2/http_connection_manager.pb.validate.h" - -#include "common/access_log/access_log_formatter.h" -#include "common/access_log/access_log_impl.h" - - -namespace Envoy{ -namespace Http{ - -struct ResponseRewriter { - absl::optional response_code_; -}; - - -class JsonFormatterImpl : public Formatter { -public: - JsonFormatterImpl(std::unordered_map formatter, - const envoy::config::filter::network::http_connection_manager::v2::HttpConnectionManager& config, - Server::Configuration::FactoryContext& context); - - // Formatter::format -const std::string format(const Http::HeaderMap* request_headers, - const Http::HeaderMap* response_headers, - const Http::HeaderMap* response_trailers, - const absl::string_view& body, - const StreamInfo::StreamInfo& stream_info) const override; - -void insertContentHeaders(const absl::string_view& body, - Http::HeaderMap* headers) const override; - -void rewriteMatchedResponse(const Http::HeaderMap* request_headers, - const Http::HeaderMap* response_headers, - const Http::HeaderMap* response_trailers, - const StreamInfo::StreamInfo& stream_info, - Code& response_code) const override; - -private: - AccessLog::FormatterPtr formatter_; - std::list> match_and_rewrite_; -}; - - -/** - * Base operator filter, compose other filters with operation - */ -class OperatorFilter : public AccessLog::Filter { -public: - OperatorFilter(const Protobuf::RepeatedPtrField< - envoy::config::filter::network::http_connection_manager::v2::ResponseMatcher>& configs, - Runtime::Loader& runtime, Runtime::RandomGenerator& random, - ProtobufMessage::ValidationVisitor& validation_visitor); - -protected: - std::vector filters_; -}; - -/** - * *And* operator filter, apply logical *and* operation to all of the sub filters. - */ -class AndFilter : public OperatorFilter { -public: - AndFilter(const envoy::config::filter::network::http_connection_manager::v2::AndFilter& config, Runtime::Loader& runtime, - Runtime::RandomGenerator& random, - ProtobufMessage::ValidationVisitor& validation_visitor); - - // AccessLog::Filter - bool evaluate(const StreamInfo::StreamInfo& info, const Http::HeaderMap& request_headers, - const Http::HeaderMap& response_headers, - const Http::HeaderMap& response_trailers) override; -}; - -/** - * *Or* operator filter, apply logical *or* operation to all of the sub filters. - */ -class OrFilter : public OperatorFilter { -public: - OrFilter(const envoy::config::filter::network::http_connection_manager::v2::OrFilter& config, Runtime::Loader& runtime, - Runtime::RandomGenerator& random, - ProtobufMessage::ValidationVisitor& validation_visitor); - - // AccessLog::Filter - bool evaluate(const StreamInfo::StreamInfo& info, const Http::HeaderMap& request_headers, - const Http::HeaderMap& response_headers, - const Http::HeaderMap& response_trailers) override; -}; - -} -} - From 7c75f6c92292fd135d2820b8e356fb4fb08d5335 Mon Sep 17 00:00:00 2001 From: Lukasz Dziedziak Date: Fri, 20 Sep 2019 23:17:12 +0200 Subject: [PATCH 13/20] added comments Signed-off-by: Lukasz Dziedziak --- .../filter/accesslog/v2/accesslog.proto | 2 + .../v2/http_connection_manager.proto | 37 ++++++++++--------- 2 files changed, 22 insertions(+), 17 deletions(-) diff --git a/api/envoy/config/filter/accesslog/v2/accesslog.proto b/api/envoy/config/filter/accesslog/v2/accesslog.proto index d777708175b5f..d876fb7f6da09 100644 --- a/api/envoy/config/filter/accesslog/v2/accesslog.proto +++ b/api/envoy/config/filter/accesslog/v2/accesslog.proto @@ -45,6 +45,8 @@ message AccessLog { } } +// [#next-major-version: In the v3 API, we should consider renaming +// it to more generic filter] message AccessLogFilter { oneof filter_specifier { option (validate.required) = true; diff --git a/api/envoy/config/filter/network/http_connection_manager/v2/http_connection_manager.proto b/api/envoy/config/filter/network/http_connection_manager/v2/http_connection_manager.proto index 60dfa42b2886d..5fdc6cc221ac7 100644 --- a/api/envoy/config/filter/network/http_connection_manager/v2/http_connection_manager.proto +++ b/api/envoy/config/filter/network/http_connection_manager/v2/http_connection_manager.proto @@ -454,28 +454,31 @@ message HttpConnectionManager { // `HTTP spec ` and is provided for convenience. bool merge_slashes = 33; - message LocalReplyConfig { - // Configuration of list of mappers which allows to filter and change local response. - // Code iterate through mappers until first match of filter. - repeated ResponseMapper mapper = 1; - - // Allows to define custom format of local reply. - oneof reply_format { - // Response body plain text format. - string format = 2; - - // Response body json format as dictionary. - google.protobuf.Struct json_format = 3; - } - }; - - // Configuration of local reply returned by Envoy. Allows to specify mapping and format of response. + // [#not-implemented-hide:] + // Configuration of local reply returned by Envoy. Allows to specify mappings and format of + // response. LocalReplyConfig local_reply_config = 35; } +message LocalReplyConfig { + // Configuration of list of mappers which allows to filter and change local response. + // Code iterate through mappers until first match of filter. + repeated ResponseMapper mapper = 1; + + // Allows to define custom format of local reply. + oneof reply_format { + // Response body plain text format. + string format = 2; + + // Response body json format as dictionary. + google.protobuf.Struct json_format = 3; + } +}; + message ResponseMapper { // Filter is used to determine if the response should be changed. - envoy.config.filter.accesslog.v2.AccessLogFilter filter = 1 [(validate.rules).message.required = true]; + envoy.config.filter.accesslog.v2.AccessLogFilter filter = 1 + [(validate.rules).message.required = true]; // Rewriter defines which values in local reply should be changed. ResponseRewriter rewriter = 2 [(validate.rules).message.required = true]; From 2670d0f6853815b22f6d70c5a6d7f5f92a50083b Mon Sep 17 00:00:00 2001 From: Lukasz Dziedziak Date: Thu, 26 Sep 2019 21:58:27 +0200 Subject: [PATCH 14/20] Added possibility to define custom format for each mapper Signed-off-by: Lukasz Dziedziak --- .../v2/http_connection_manager.proto | 8 ++++++++ tools/spelling_dictionary.txt | 1 + 2 files changed, 9 insertions(+) diff --git a/api/envoy/config/filter/network/http_connection_manager/v2/http_connection_manager.proto b/api/envoy/config/filter/network/http_connection_manager/v2/http_connection_manager.proto index 5fdc6cc221ac7..908576a0d8f41 100644 --- a/api/envoy/config/filter/network/http_connection_manager/v2/http_connection_manager.proto +++ b/api/envoy/config/filter/network/http_connection_manager/v2/http_connection_manager.proto @@ -482,6 +482,14 @@ message ResponseMapper { // Rewriter defines which values in local reply should be changed. ResponseRewriter rewriter = 2 [(validate.rules).message.required = true]; + + oneof reply_format { + // Response body plain text format. + string format = 3; + + // Response body json format as dictionary. + google.protobuf.Struct json_format = 4; + } } // Configuration of new value for matched local response. diff --git a/tools/spelling_dictionary.txt b/tools/spelling_dictionary.txt index 0cd9883bd93b6..eb6d58b35d5c8 100644 --- a/tools/spelling_dictionary.txt +++ b/tools/spelling_dictionary.txt @@ -711,6 +711,7 @@ resolvers resync ret retriable +rewriter rpcs rq rtrim From cd31254449576c223d9e3c0cb6bb3ea5ed604b11 Mon Sep 17 00:00:00 2001 From: Lukasz Dziedziak Date: Fri, 27 Sep 2019 11:03:56 +0200 Subject: [PATCH 15/20] Extracted new format StringOrJson Signed-off-by: Lukasz Dziedziak --- .../network/http_connection_manager/v2/BUILD | 1 + .../v2/http_connection_manager.proto | 17 ++-------------- api/envoy/type/BUILD | 6 ++++++ api/envoy/type/format.proto | 20 +++++++++++++++++++ 4 files changed, 29 insertions(+), 15 deletions(-) create mode 100644 api/envoy/type/format.proto diff --git a/api/envoy/config/filter/network/http_connection_manager/v2/BUILD b/api/envoy/config/filter/network/http_connection_manager/v2/BUILD index 6a090f3a115d2..ce5a0afc000fd 100644 --- a/api/envoy/config/filter/network/http_connection_manager/v2/BUILD +++ b/api/envoy/config/filter/network/http_connection_manager/v2/BUILD @@ -21,6 +21,7 @@ api_proto_library_internal( "//envoy/api/v2/core:config_source", "//envoy/api/v2/core:protocol", "//envoy/config/filter/accesslog/v2:accesslog", + "//envoy/type:format", "//envoy/type:percent", ], ) diff --git a/api/envoy/config/filter/network/http_connection_manager/v2/http_connection_manager.proto b/api/envoy/config/filter/network/http_connection_manager/v2/http_connection_manager.proto index 015e64f1e9da8..a7a925fa9ea73 100644 --- a/api/envoy/config/filter/network/http_connection_manager/v2/http_connection_manager.proto +++ b/api/envoy/config/filter/network/http_connection_manager/v2/http_connection_manager.proto @@ -12,6 +12,7 @@ import "envoy/api/v2/rds.proto"; import "envoy/api/v2/srds.proto"; import "envoy/config/filter/accesslog/v2/accesslog.proto"; import "envoy/type/percent.proto"; +import "envoy/type/format.proto"; import "google/protobuf/any.proto"; import "google/protobuf/duration.proto"; @@ -469,13 +470,7 @@ message LocalReplyConfig { repeated ResponseMapper mapper = 1; // Allows to define custom format of local reply. - oneof reply_format { - // Response body plain text format. - string format = 2; - - // Response body json format as dictionary. - google.protobuf.Struct json_format = 3; - } + type.StringOrJson format = 2; }; message ResponseMapper { @@ -485,14 +480,6 @@ message ResponseMapper { // Rewriter defines which values in local reply should be changed. ResponseRewriter rewriter = 2 [(validate.rules).message.required = true]; - - oneof reply_format { - // Response body plain text format. - string format = 3; - - // Response body json format as dictionary. - google.protobuf.Struct json_format = 4; - } } // Configuration of new value for matched local response. diff --git a/api/envoy/type/BUILD b/api/envoy/type/BUILD index 26dd9730d9eaa..41bebadecd614 100644 --- a/api/envoy/type/BUILD +++ b/api/envoy/type/BUILD @@ -6,6 +6,12 @@ api_proto_package( name = "type", ) +api_proto_library_internal( + name = "format", + srcs = ["format.proto"], + visibility = ["//visibility:public"], +) + api_proto_library_internal( name = "http_status", srcs = ["http_status.proto"], diff --git a/api/envoy/type/format.proto b/api/envoy/type/format.proto new file mode 100644 index 0000000000000..2b84189085b2f --- /dev/null +++ b/api/envoy/type/format.proto @@ -0,0 +1,20 @@ +syntax = "proto3"; + +package envoy.type; + +option java_outer_classname = "FormatProto"; +option java_multiple_files = true; +option java_package = "io.envoyproxy.envoy.type"; + +import "google/protobuf/struct.proto"; + +message StringOrJson { + // Allows to define custom format of returned data. + oneof format { + // Plain text format. + string string_format = 2; + + // Json format as dictionary. + google.protobuf.Struct json_format = 3; + } +} \ No newline at end of file From a77c82f042f1938bce0c5914dba2c0a3cc943f3f Mon Sep 17 00:00:00 2001 From: Lukasz Dziedziak Date: Tue, 1 Oct 2019 15:33:44 +0200 Subject: [PATCH 16/20] Removed docs and fixed format. I will provide docs file with implementation Signed-off-by: Lukasz Dziedziak --- api/envoy/type/format.proto | 2 +- .../http/http_conn_man/http_conn_man.rst | 1 - .../http/http_conn_man/local_reply.rst | 103 ------------------ .../observability/access_log.rst | 2 - 4 files changed, 1 insertion(+), 107 deletions(-) delete mode 100644 docs/root/configuration/http/http_conn_man/local_reply.rst diff --git a/api/envoy/type/format.proto b/api/envoy/type/format.proto index 2b84189085b2f..e9f65ac62b01d 100644 --- a/api/envoy/type/format.proto +++ b/api/envoy/type/format.proto @@ -17,4 +17,4 @@ message StringOrJson { // Json format as dictionary. google.protobuf.Struct json_format = 3; } -} \ No newline at end of file +} diff --git a/docs/root/configuration/http/http_conn_man/http_conn_man.rst b/docs/root/configuration/http/http_conn_man/http_conn_man.rst index fa32da03e9745..ff9b3857a52fb 100644 --- a/docs/root/configuration/http/http_conn_man/http_conn_man.rst +++ b/docs/root/configuration/http/http_conn_man/http_conn_man.rst @@ -14,4 +14,3 @@ HTTP connection manager stats runtime rds - local_reply diff --git a/docs/root/configuration/http/http_conn_man/local_reply.rst b/docs/root/configuration/http/http_conn_man/local_reply.rst deleted file mode 100644 index 1ef3fe847a0aa..0000000000000 --- a/docs/root/configuration/http/http_conn_man/local_reply.rst +++ /dev/null @@ -1,103 +0,0 @@ -.. _config_http_conn_man_local_reply: - -Local reply modification -======================== - -The :ref:`HTTP connection manager ` supports modification of local reply which is response returned by Envoy itself -rather than response from cluster. - -Features: - -* :ref:`Local reply content modification`. -* :ref:`Local reply format modification`. - -.. _config_http_conn_man_local_reply_modification: - -Local reply content modification --------------------------------- - -There is support for modification of local replies. You can specify list of :ref:`mappers ` which contains -pairs of :ref:`filter ` and :ref:`rewriter `. Both elements in pair has to be -specified. If more than one pair is defined then first matching is used. - -Example how to change status code when local reply contains any of these response flags: - -.. code-block:: yaml - - mapper: - filter: - response_flag_filter: - flags: - - LH - - UH - rewriter: - status_code: 504 - -.. _config_http_conn_man_local_reply_format: - -Local reply format modification -------------------------------- - -Local reply format contains command operators that extract the relevant data and insert it. -They support two formats: :ref:`format strings ` and -:ref:`"format dictionaries" `. In both cases, the :ref:`command operators ` -are used to extract the relevant data, which is then inserted into the specified reply format. -Only one reply format may be specified at the time. - -.. _config_http_conn_man_local_reply_format_string: - -Format Strings --------------- - -Format strings are plain strings, specified using the ``format`` key. They may contain -either :ref:`command operators ` or other characters interpreted as a plain string. -The access log formatter does not make any assumptions about a new line separator, so one -has to specified as part of the format string. - -.. code-block:: none - - %RESP_BODY% %RESPONSE_CODE% %RESPONSE_FLAGS% "My custom response" - -Example of custom Envoy local reply format: - -.. code-block:: none - - upstream connect error or disconnect/reset before headers. reset reason: connection failure 204 UH My custom response - - -If format isn't specified then :ref:`default format ` is used. - -.. _config_http_conn_man_local_reply_default_format: - -Default Format String ---------------------- - -If custom format string is not specified, Envoy uses the following default format: - -.. code-block:: none - - %RESP_BODY% - -Example of the default local reply format: - -.. code-block:: none - - upstream connect error or disconnect/reset before headers. reset reason: connection failure - -.. _config_http_conn_man_local_reply_dictionaries: - -Format Dictionaries -------------------- - -Format dictionaries are dictionaries that specify a structured local reply output format, -specified using the ``json_format`` key. This allows response to be returned in a structured format -such as JSON. - -More can be found in :ref:`configuration `. - -.. _config_http_conn_man_local_reply_command_operators: - -Command Operators ------------------ - -Local reply format reuse :ref:`access log operators `, so more information can be found there. diff --git a/docs/root/configuration/observability/access_log.rst b/docs/root/configuration/observability/access_log.rst index 9c7df9d7e10c1..7ec4b57f08006 100644 --- a/docs/root/configuration/observability/access_log.rst +++ b/docs/root/configuration/observability/access_log.rst @@ -91,8 +91,6 @@ Format dictionaries have the following restrictions: * The dictionary must map strings to strings (specifically, strings to command operators). Nesting is not currently supported. -.. _config_access_log_command_operators: - Command Operators ----------------- From 9c8d7574e8bdd33465ae65f63ba9442147091eb3 Mon Sep 17 00:00:00 2001 From: Lukasz Dziedziak Date: Wed, 2 Oct 2019 23:12:19 +0200 Subject: [PATCH 17/20] Added more docs Signed-off-by: Lukasz Dziedziak --- .../v2/http_connection_manager.proto | 2 ++ api/envoy/type/format.proto | 34 ++++++++++++++++--- docs/root/api-v2/types/types.rst | 1 + .../observability/access_log.rst | 2 ++ 4 files changed, 34 insertions(+), 5 deletions(-) diff --git a/api/envoy/config/filter/network/http_connection_manager/v2/http_connection_manager.proto b/api/envoy/config/filter/network/http_connection_manager/v2/http_connection_manager.proto index a7a925fa9ea73..97f591222376e 100644 --- a/api/envoy/config/filter/network/http_connection_manager/v2/http_connection_manager.proto +++ b/api/envoy/config/filter/network/http_connection_manager/v2/http_connection_manager.proto @@ -470,6 +470,8 @@ message LocalReplyConfig { repeated ResponseMapper mapper = 1; // Allows to define custom format of local reply. + // It is allowed to use :ref:`command operators ` + // which will be resolved to actual data. type.StringOrJson format = 2; }; diff --git a/api/envoy/type/format.proto b/api/envoy/type/format.proto index e9f65ac62b01d..dcb02ce901a90 100644 --- a/api/envoy/type/format.proto +++ b/api/envoy/type/format.proto @@ -8,13 +8,37 @@ option java_package = "io.envoyproxy.envoy.type"; import "google/protobuf/struct.proto"; +// [#protodoc-title: Format] + +// Allows to define custom format of returned data. message StringOrJson { - // Allows to define custom format of returned data. + oneof format { - // Plain text format. - string string_format = 2; + // Plain text format. Allows to specify some custom message to returns. + // + // .. code-block:: yaml + // + // string_format: "My custom message" + // + string string_format = 1; - // Json format as dictionary. - google.protobuf.Struct json_format = 3; + // Json format as dictionary. Allows to specify some custom message to return in json format. + // + // .. code-block:: yaml + // + // json_format: + // protocol: "HTTP/1.1" + // message: "My message" + // + // The following JSON object would be returned: + // + // .. code-block:: json + // + // { + // "protocol": "HTTP/1.1", + // "message": "My message" + // } + // + google.protobuf.Struct json_format = 2; } } diff --git a/docs/root/api-v2/types/types.rst b/docs/root/api-v2/types/types.rst index a5a84c33a13d1..4ec77b14becf2 100644 --- a/docs/root/api-v2/types/types.rst +++ b/docs/root/api-v2/types/types.rst @@ -5,6 +5,7 @@ Types :glob: :maxdepth: 2 + ../type/format.proto ../type/http_status.proto ../type/percent.proto ../type/range.proto diff --git a/docs/root/configuration/observability/access_log.rst b/docs/root/configuration/observability/access_log.rst index 7ec4b57f08006..9c7df9d7e10c1 100644 --- a/docs/root/configuration/observability/access_log.rst +++ b/docs/root/configuration/observability/access_log.rst @@ -91,6 +91,8 @@ Format dictionaries have the following restrictions: * The dictionary must map strings to strings (specifically, strings to command operators). Nesting is not currently supported. +.. _config_access_log_command_operators: + Command Operators ----------------- From 77841306f1b82f3895a65d373271e1a9cef49398 Mon Sep 17 00:00:00 2001 From: Lukasz Dziedziak Date: Fri, 4 Oct 2019 22:54:40 +0200 Subject: [PATCH 18/20] Code review fix Signed-off-by: Lukasz Dziedziak --- .../v2/http_connection_manager.proto | 2 +- api/envoy/type/format.proto | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/api/envoy/config/filter/network/http_connection_manager/v2/http_connection_manager.proto b/api/envoy/config/filter/network/http_connection_manager/v2/http_connection_manager.proto index 97f591222376e..20072d3c2aaf3 100644 --- a/api/envoy/config/filter/network/http_connection_manager/v2/http_connection_manager.proto +++ b/api/envoy/config/filter/network/http_connection_manager/v2/http_connection_manager.proto @@ -466,7 +466,7 @@ message HttpConnectionManager { message LocalReplyConfig { // Configuration of list of mappers which allows to filter and change local response. - // Code iterate through mappers until first match of filter. + // The client will iterate through mappers until first match. repeated ResponseMapper mapper = 1; // Allows to define custom format of local reply. diff --git a/api/envoy/type/format.proto b/api/envoy/type/format.proto index dcb02ce901a90..6ded14c5d350d 100644 --- a/api/envoy/type/format.proto +++ b/api/envoy/type/format.proto @@ -10,11 +10,11 @@ import "google/protobuf/struct.proto"; // [#protodoc-title: Format] -// Allows to define custom format of returned data. +// Allows to define one of format: flat plain text or structured json. message StringOrJson { oneof format { - // Plain text format. Allows to specify some custom message to returns. + // Allows to specify flat plain text format. // // .. code-block:: yaml // @@ -22,7 +22,7 @@ message StringOrJson { // string string_format = 1; - // Json format as dictionary. Allows to specify some custom message to return in json format. + // Allows to specify structured data as json. // // .. code-block:: yaml // @@ -30,7 +30,7 @@ message StringOrJson { // protocol: "HTTP/1.1" // message: "My message" // - // The following JSON object would be returned: + // The following JSON object would be created: // // .. code-block:: json // From 5eadeca73c335b9858ca62f68ff4b52f5da8a872 Mon Sep 17 00:00:00 2001 From: Lukasz Dziedziak Date: Fri, 11 Oct 2019 17:56:17 +0200 Subject: [PATCH 19/20] Fix build Signed-off-by: Lukasz Dziedziak --- .../v2/http_connection_manager.proto | 11 ++++------- api/envoy/type/format.proto | 1 - 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/api/envoy/config/filter/network/http_connection_manager/v2/http_connection_manager.proto b/api/envoy/config/filter/network/http_connection_manager/v2/http_connection_manager.proto index 5c78c621f71a1..001cf9874260c 100644 --- a/api/envoy/config/filter/network/http_connection_manager/v2/http_connection_manager.proto +++ b/api/envoy/config/filter/network/http_connection_manager/v2/http_connection_manager.proto @@ -11,8 +11,8 @@ import "envoy/api/v2/core/protocol.proto"; import "envoy/api/v2/rds.proto"; import "envoy/api/v2/srds.proto"; import "envoy/config/filter/accesslog/v2/accesslog.proto"; -import "envoy/type/percent.proto"; import "envoy/type/format.proto"; +import "envoy/type/percent.proto"; import "google/protobuf/any.proto"; import "google/protobuf/duration.proto"; @@ -478,23 +478,20 @@ message LocalReplyConfig { // It is allowed to use :ref:`command operators ` // which will be resolved to actual data. type.StringOrJson format = 2; -}; +} message ResponseMapper { // Filter is used to determine if the response should be changed. - envoy.config.filter.accesslog.v2.AccessLogFilter filter = 1 - [(validate.rules).message.required = true]; + accesslog.v2.AccessLogFilter filter = 1 [(validate.rules).message = {required: true}]; // Rewriter defines which values in local reply should be changed. - ResponseRewriter rewriter = 2 [(validate.rules).message.required = true]; + ResponseRewriter rewriter = 2 [(validate.rules).message = {required: true}]; } // Configuration of new value for matched local response. message ResponseRewriter { // Status code for matched response. google.protobuf.UInt32Value status_code = 1; - - // TODO: add support for GRPC rewrite. } message Rds { diff --git a/api/envoy/type/format.proto b/api/envoy/type/format.proto index 6ded14c5d350d..4918b18816f13 100644 --- a/api/envoy/type/format.proto +++ b/api/envoy/type/format.proto @@ -12,7 +12,6 @@ import "google/protobuf/struct.proto"; // Allows to define one of format: flat plain text or structured json. message StringOrJson { - oneof format { // Allows to specify flat plain text format. // From 0aee07ae8e9251267b29ae54a36ee91ec57b9599 Mon Sep 17 00:00:00 2001 From: Lukasz Dziedziak Date: Fri, 11 Oct 2019 20:51:45 +0200 Subject: [PATCH 20/20] Generated v3 files Signed-off-by: Lukasz Dziedziak --- .../filter/accesslog/v3alpha/accesslog.proto | 2 + .../v3alpha/http_connection_manager.proto | 33 +++++++++- api/envoy/type/v3alpha/format.proto | 43 +++++++++++++ .../config/api_type_db.generated.pb_text | 64 +++++++++++++++++++ 4 files changed, 141 insertions(+), 1 deletion(-) create mode 100644 api/envoy/type/v3alpha/format.proto diff --git a/api/envoy/config/filter/accesslog/v3alpha/accesslog.proto b/api/envoy/config/filter/accesslog/v3alpha/accesslog.proto index a257f4a229891..f4e87ef59ab86 100644 --- a/api/envoy/config/filter/accesslog/v3alpha/accesslog.proto +++ b/api/envoy/config/filter/accesslog/v3alpha/accesslog.proto @@ -45,6 +45,8 @@ message AccessLog { } } +// [#next-major-version: In the v3 API, we should consider renaming +// it to more generic filter] message AccessLogFilter { oneof filter_specifier { option (validate.required) = true; diff --git a/api/envoy/config/filter/network/http_connection_manager/v3alpha/http_connection_manager.proto b/api/envoy/config/filter/network/http_connection_manager/v3alpha/http_connection_manager.proto index 9fe3396831f5a..88bd1e8c93337 100644 --- a/api/envoy/config/filter/network/http_connection_manager/v3alpha/http_connection_manager.proto +++ b/api/envoy/config/filter/network/http_connection_manager/v3alpha/http_connection_manager.proto @@ -12,6 +12,7 @@ import "envoy/api/v3alpha/rds.proto"; import "envoy/api/v3alpha/srds.proto"; import "envoy/config/filter/accesslog/v3alpha/accesslog.proto"; import "envoy/config/filter/network/http_connection_manager/v2/http_connection_manager.proto"; +import "envoy/type/v3alpha/format.proto"; import "envoy/type/v3alpha/percent.proto"; import "google/protobuf/any.proto"; @@ -24,7 +25,7 @@ import "validate/validate.proto"; // [#protodoc-title: HTTP connection manager] // HTTP connection manager :ref:`configuration overview `. -// [#comment:next free field: 36] +// [#comment:next free field: 37] message HttpConnectionManager { enum CodecType { // For every new connection, the connection manager will determine which @@ -449,6 +450,36 @@ message HttpConnectionManager { // with `prefix` match set to `/dir`. Defaults to `false`. Note that slash merging is not part of // `HTTP spec ` and is provided for convenience. bool merge_slashes = 33; + + // [#not-implemented-hide:] + // Configuration of local reply returned by Envoy. Allows to specify mappings and format of + // response. + LocalReplyConfig local_reply_config = 36; +} + +message LocalReplyConfig { + // Configuration of list of mappers which allows to filter and change local response. + // The client will iterate through mappers until first match. + repeated ResponseMapper mapper = 1; + + // Allows to define custom format of local reply. + // It is allowed to use :ref:`command operators ` + // which will be resolved to actual data. + type.v3alpha.StringOrJson format = 2; +} + +message ResponseMapper { + // Filter is used to determine if the response should be changed. + accesslog.v3alpha.AccessLogFilter filter = 1 [(validate.rules).message = {required: true}]; + + // Rewriter defines which values in local reply should be changed. + ResponseRewriter rewriter = 2 [(validate.rules).message = {required: true}]; +} + +// Configuration of new value for matched local response. +message ResponseRewriter { + // Status code for matched response. + google.protobuf.UInt32Value status_code = 1; } message Rds { diff --git a/api/envoy/type/v3alpha/format.proto b/api/envoy/type/v3alpha/format.proto new file mode 100644 index 0000000000000..cc0ee55745611 --- /dev/null +++ b/api/envoy/type/v3alpha/format.proto @@ -0,0 +1,43 @@ +syntax = "proto3"; + +package envoy.type.v3alpha; + +option java_outer_classname = "FormatProto"; +option java_multiple_files = true; +option java_package = "io.envoyproxy.envoy.type.v3alpha"; + +import "google/protobuf/struct.proto"; + +// [#protodoc-title: Format] + +// Allows to define one of format: flat plain text or structured json. +message StringOrJson { + oneof format { + // Allows to specify flat plain text format. + // + // .. code-block:: yaml + // + // string_format: "My custom message" + // + string string_format = 1; + + // Allows to specify structured data as json. + // + // .. code-block:: yaml + // + // json_format: + // protocol: "HTTP/1.1" + // message: "My message" + // + // The following JSON object would be created: + // + // .. code-block:: json + // + // { + // "protocol": "HTTP/1.1", + // "message": "My message" + // } + // + google.protobuf.Struct json_format = 2; + } +} diff --git a/source/common/config/api_type_db.generated.pb_text b/source/common/config/api_type_db.generated.pb_text index dd963044eb702..2d2895e397eb0 100644 --- a/source/common/config/api_type_db.generated.pb_text +++ b/source/common/config/api_type_db.generated.pb_text @@ -4913,6 +4913,14 @@ types { next_version_type_name: "envoy.config.filter.network.http_connection_manager.v3alpha.HttpFilter" } } +types { + key: "envoy.config.filter.network.http_connection_manager.v2.LocalReplyConfig" + value { + qualified_package: "envoy.config.filter.network.http_connection_manager.v2" + proto_path: "envoy/config/filter/network/http_connection_manager/v2/http_connection_manager.proto" + next_version_type_name: "envoy.config.filter.network.http_connection_manager.v3alpha.LocalReplyConfig" + } +} types { key: "envoy.config.filter.network.http_connection_manager.v2.Rds" value { @@ -4921,6 +4929,22 @@ types { next_version_type_name: "envoy.config.filter.network.http_connection_manager.v3alpha.Rds" } } +types { + key: "envoy.config.filter.network.http_connection_manager.v2.ResponseMapper" + value { + qualified_package: "envoy.config.filter.network.http_connection_manager.v2" + proto_path: "envoy/config/filter/network/http_connection_manager/v2/http_connection_manager.proto" + next_version_type_name: "envoy.config.filter.network.http_connection_manager.v3alpha.ResponseMapper" + } +} +types { + key: "envoy.config.filter.network.http_connection_manager.v2.ResponseRewriter" + value { + qualified_package: "envoy.config.filter.network.http_connection_manager.v2" + proto_path: "envoy/config/filter/network/http_connection_manager/v2/http_connection_manager.proto" + next_version_type_name: "envoy.config.filter.network.http_connection_manager.v3alpha.ResponseRewriter" + } +} types { key: "envoy.config.filter.network.http_connection_manager.v2.ScopedRds" value { @@ -5047,6 +5071,13 @@ types { proto_path: "envoy/config/filter/network/http_connection_manager/v3alpha/http_connection_manager.proto" } } +types { + key: "envoy.config.filter.network.http_connection_manager.v3alpha.LocalReplyConfig" + value { + qualified_package: "envoy.config.filter.network.http_connection_manager.v3alpha" + proto_path: "envoy/config/filter/network/http_connection_manager/v3alpha/http_connection_manager.proto" + } +} types { key: "envoy.config.filter.network.http_connection_manager.v3alpha.Rds" value { @@ -5054,6 +5085,20 @@ types { proto_path: "envoy/config/filter/network/http_connection_manager/v3alpha/http_connection_manager.proto" } } +types { + key: "envoy.config.filter.network.http_connection_manager.v3alpha.ResponseMapper" + value { + qualified_package: "envoy.config.filter.network.http_connection_manager.v3alpha" + proto_path: "envoy/config/filter/network/http_connection_manager/v3alpha/http_connection_manager.proto" + } +} +types { + key: "envoy.config.filter.network.http_connection_manager.v3alpha.ResponseRewriter" + value { + qualified_package: "envoy.config.filter.network.http_connection_manager.v3alpha" + proto_path: "envoy/config/filter/network/http_connection_manager/v3alpha/http_connection_manager.proto" + } +} types { key: "envoy.config.filter.network.http_connection_manager.v3alpha.ScopedRds" value { @@ -7573,6 +7618,14 @@ types { next_version_type_name: "envoy.type.v3alpha.StatusCode" } } +types { + key: "envoy.type.StringOrJson" + value { + qualified_package: "envoy.type" + proto_path: "envoy/type/format.proto" + next_version_type_name: "envoy.type.v3alpha.StringOrJson" + } +} types { key: "envoy.type.matcher.DoubleMatcher" value { @@ -7772,6 +7825,13 @@ types { proto_path: "envoy/type/v3alpha/http_status.proto" } } +types { + key: "envoy.type.v3alpha.StringOrJson" + value { + qualified_package: "envoy.type.v3alpha" + proto_path: "envoy/type/v3alpha/format.proto" + } +} next_version_packages { key: "envoy.admin.v2alpha" value: "envoy.admin.v3alpha" @@ -8380,6 +8440,10 @@ next_version_proto_paths { key: "envoy/service/trace/v2/trace_service.proto" value: "envoy/service/trace/v3alpha/trace_service.proto" } +next_version_proto_paths { + key: "envoy/type/format.proto" + value: "envoy/type/v3alpha/format.proto" +} next_version_proto_paths { key: "envoy/type/http_status.proto" value: "envoy/type/v3alpha/http_status.proto"