diff --git a/DEPRECATED.md b/DEPRECATED.md index e5308f46e43ea..955494c23b6e5 100644 --- a/DEPRECATED.md +++ b/DEPRECATED.md @@ -24,6 +24,8 @@ A logged warning is expected for each deprecated item that is in deprecation win [HttpConnectionManager](https://github.com/envoyproxy/envoy/blob/master/api/envoy/config/filter/network/http_connection_manager/v2/http_connection_manager.proto) instead. * Setting hosts via `hosts` field in `Cluster` is deprecated. Use `load_assignment` instead. +* Use of `response_headers_to_*` and `request_headers_to_add` are deprecated at the `RouteAction` + level. Please use the configuration options at the `Route` level. ## Version 1.7.0 diff --git a/api/envoy/api/v2/route/route.proto b/api/envoy/api/v2/route/route.proto index 0a3bb20ee7491..a497a1871f9e9 100644 --- a/api/envoy/api/v2/route/route.proto +++ b/api/envoy/api/v2/route/route.proto @@ -75,7 +75,7 @@ message VirtualHost { // Specifies a list of HTTP headers that should be added to each request // handled by this virtual host. Headers specified at this level are applied - // after headers from enclosed :ref:`envoy_api_msg_route.RouteAction` and before headers from the + // after headers from enclosed :ref:`envoy_api_msg_route.Route` and before headers from the // enclosing :ref:`envoy_api_msg_RouteConfiguration`. For more information, including // details on header value syntax, see the documentation on :ref:`custom request headers // `. @@ -83,7 +83,7 @@ message VirtualHost { // Specifies a list of HTTP headers that should be added to each response // handled by this virtual host. Headers specified at this level are applied - // after headers from enclosed :ref:`envoy_api_msg_route.RouteAction` and before headers from the + // after headers from enclosed :ref:`envoy_api_msg_route.Route` and before headers from the // enclosing :ref:`envoy_api_msg_RouteConfiguration`. For more information, including // details on header value syntax, see the documentation on :ref:`custom request headers // `. @@ -148,6 +148,26 @@ message Route { // specific; see the :ref:`HTTP filter documentation ` for // if and how it is utilized. map per_filter_config = 8; + + // Specifies a set of headers that will be added to requests matching this + // route. Headers specified at this level are applied before headers from the + // enclosing :ref:`envoy_api_msg_route.VirtualHost` and + // :ref:`envoy_api_msg_RouteConfiguration`. For more information, including details on + // header value syntax, see the documentation on :ref:`custom request headers + // `. + repeated core.HeaderValueOption request_headers_to_add = 9; + + // Specifies a set of headers that will be added to responses to requests + // matching this route. Headers specified at this level are applied before + // headers from the enclosing :ref:`envoy_api_msg_route.VirtualHost` and + // :ref:`envoy_api_msg_RouteConfiguration`. For more information, including + // details on header value syntax, see the documentation on + // :ref:`custom request headers `. + repeated core.HeaderValueOption response_headers_to_add = 10; + + // Specifies a list of HTTP headers that should be removed from each response + // to requests matching this route. + repeated string response_headers_to_remove = 11; } // Compared to the :ref:`cluster ` field that specifies a @@ -176,8 +196,7 @@ message WeightedCluster { // Specifies a list of headers to be added to requests when this cluster is selected // through the enclosing :ref:`envoy_api_msg_route.RouteAction`. // Headers specified at this level are applied before headers from the enclosing - // :ref:`envoy_api_msg_route.RouteAction`, - // :ref:`envoy_api_msg_route.VirtualHost`, and + // :ref:`envoy_api_msg_route.Route`, :ref:`envoy_api_msg_route.VirtualHost`, and // :ref:`envoy_api_msg_RouteConfiguration`. For more information, including details on // header value syntax, see the documentation on :ref:`custom request headers // `. @@ -186,8 +205,7 @@ message WeightedCluster { // Specifies a list of headers to be added to responses when this cluster is selected // through the enclosing :ref:`envoy_api_msg_route.RouteAction`. // Headers specified at this level are applied before headers from the enclosing - // :ref:`envoy_api_msg_route.RouteAction`, - // :ref:`envoy_api_msg_route.VirtualHost`, and + // :ref:`envoy_api_msg_route.Route`, :ref:`envoy_api_msg_route.VirtualHost`, and // :ref:`envoy_api_msg_RouteConfiguration`. For more information, including details on // header value syntax, see the documentation on :ref:`custom request headers // `. @@ -492,25 +510,14 @@ message RouteAction { // https://github.com/lyft/protoc-gen-validate/issues/42 is resolved.] core.RoutingPriority priority = 11; - // Specifies a set of headers that will be added to requests matching this - // route. Headers specified at this level are applied before headers from the - // enclosing :ref:`envoy_api_msg_route.VirtualHost` and - // :ref:`envoy_api_msg_RouteConfiguration`. For more information, including details on - // header value syntax, see the documentation on :ref:`custom request headers - // `. - repeated core.HeaderValueOption request_headers_to_add = 12; + // [#not-implemented-hide:] + repeated core.HeaderValueOption request_headers_to_add = 12 [deprecated = true]; - // Specifies a set of headers that will be added to responses to requests - // matching this route. Headers specified at this level are applied before - // headers from the enclosing :ref:`envoy_api_msg_route.VirtualHost` and - // :ref:`envoy_api_msg_RouteConfiguration`. For more information, including - // details on header value syntax, see the documentation on - // :ref:`custom request headers `. - repeated core.HeaderValueOption response_headers_to_add = 18; + // [#not-implemented-hide:] + repeated core.HeaderValueOption response_headers_to_add = 18 [deprecated = true]; - // Specifies a list of HTTP headers that should be removed from each response - // to requests matching this route. - repeated string response_headers_to_remove = 19; + // [#not-implemented-hide:] + repeated string response_headers_to_remove = 19 [deprecated = true]; // Specifies a set of rate limit configurations that could be applied to the // route. @@ -711,8 +718,9 @@ message DirectResponseAction { // // .. note:: // - // Headers can be specified using *response_headers_to_add* in - // :ref:`envoy_api_msg_RouteConfiguration`. + // Headers can be specified using *response_headers_to_add* in the enclosing + // :ref:`envoy_api_msg_route.Route`, :ref:`envoy_api_msg_RouteConfiguration` or + // :ref:`envoy_api_msg_route.VirtualHost`. core.DataSource body = 2; } diff --git a/docs/root/intro/version_history.rst b/docs/root/intro/version_history.rst index 121c40993e0fb..4d97801340399 100644 --- a/docs/root/intro/version_history.rst +++ b/docs/root/intro/version_history.rst @@ -43,6 +43,7 @@ Version history :ref:`use_data_plane_proto` boolean flag in the ratelimit configuration. Support for the legacy proto :repo:`source/common/ratelimit/ratelimit.proto` is deprecated and will be removed at the start of the 1.9.0 release cycle. +* router: added ability to set request/response headers at the :ref:`envoy_api_msg_route.Route` level. * tracing: added support for configuration of :ref:`tracing sampling `. * upstream: added configuration option to the subset load balancer to take locality weights into account when diff --git a/source/common/router/config_impl.cc b/source/common/router/config_impl.cc index 5288a8143640b..d5301073fd1ac 100644 --- a/source/common/router/config_impl.cc +++ b/source/common/router/config_impl.cc @@ -270,9 +270,13 @@ RouteEntryImplBase::RouteEntryImplBase(const VirtualHostImpl& vhost, priority_(ConfigUtility::parsePriority(route.route().priority())), total_cluster_weight_( PROTOBUF_GET_WRAPPED_OR_DEFAULT(route.route().weighted_clusters(), total_weight, 100UL)), - request_headers_parser_(HeaderParser::configure(route.route().request_headers_to_add())), - response_headers_parser_(HeaderParser::configure(route.route().response_headers_to_add(), - route.route().response_headers_to_remove())), + route_action_request_headers_parser_( + HeaderParser::configure(route.route().request_headers_to_add())), + route_action_response_headers_parser_(HeaderParser::configure( + route.route().response_headers_to_add(), route.route().response_headers_to_remove())), + request_headers_parser_(HeaderParser::configure(route.request_headers_to_add())), + response_headers_parser_(HeaderParser::configure(route.response_headers_to_add(), + route.response_headers_to_remove())), opaque_config_(parseOpaqueConfig(route)), decorator_(parseDecorator(route)), direct_response_code_(ConfigUtility::parseDirectResponseCode(route)), direct_response_body_(ConfigUtility::parseDirectResponseBody(route)), @@ -369,8 +373,10 @@ Http::WebSocketProxyPtr RouteEntryImplBase::createWebSocketProxy( void RouteEntryImplBase::finalizeRequestHeaders(Http::HeaderMap& headers, const RequestInfo::RequestInfo& request_info, bool insert_envoy_original_path) const { - // Append user-specified request headers in the following order: route-level headers, - // virtual host level headers and finally global connection manager level headers. + // Append user-specified request headers in the following order: route-action-level headers, + // route-level headers, virtual host level headers and finally global connection manager level + // headers. + route_action_request_headers_parser_->evaluateHeaders(headers, request_info); request_headers_parser_->evaluateHeaders(headers, request_info); vhost_.requestHeaderParser().evaluateHeaders(headers, request_info); vhost_.globalRouteConfig().requestHeaderParser().evaluateHeaders(headers, request_info); @@ -386,6 +392,10 @@ void RouteEntryImplBase::finalizeRequestHeaders(Http::HeaderMap& headers, void RouteEntryImplBase::finalizeResponseHeaders( Http::HeaderMap& headers, const RequestInfo::RequestInfo& request_info) const { + // Append user-specified response headers in the following order: route-action-level headers, + // route-level headers, virtual host level headers and finally global connection manager level + // headers. + route_action_response_headers_parser_->evaluateHeaders(headers, request_info); response_headers_parser_->evaluateHeaders(headers, request_info); vhost_.responseHeaderParser().evaluateHeaders(headers, request_info); vhost_.globalRouteConfig().responseHeaderParser().evaluateHeaders(headers, request_info); diff --git a/source/common/router/config_impl.h b/source/common/router/config_impl.h index e5c79a6c62229..238f54b99d51b 100644 --- a/source/common/router/config_impl.h +++ b/source/common/router/config_impl.h @@ -359,8 +359,6 @@ class RouteEntryImplBase : public RouteEntry, void finalizePathHeader(Http::HeaderMap& headers, const std::string& matched_path, bool insert_envoy_original_path) const; - const HeaderParser& requestHeaderParser() const { return *request_headers_parser_; }; - const HeaderParser& responseHeaderParser() const { return *response_headers_parser_; }; private: struct RuntimeData { @@ -535,6 +533,8 @@ class RouteEntryImplBase : public RouteEntry, const uint64_t total_cluster_weight_; std::unique_ptr hash_policy_; MetadataMatchCriteriaConstPtr metadata_match_criteria_; + HeaderParserPtr route_action_request_headers_parser_; + HeaderParserPtr route_action_response_headers_parser_; HeaderParserPtr request_headers_parser_; HeaderParserPtr response_headers_parser_; envoy::api::v2::core::Metadata metadata_; diff --git a/test/common/router/config_impl_test.cc b/test/common/router/config_impl_test.cc index 63c942be9dc6a..eed552b9bc55b 100644 --- a/test/common/router/config_impl_test.cc +++ b/test/common/router/config_impl_test.cc @@ -532,7 +532,7 @@ TEST(RouteMatcherTest, TestRoutesWithInvalidRegex) { EnvoyException, "Invalid regex '\\^/\\(\\+invalid\\)':"); } -// Validates behavior of request_headers_to_add at router, vhost, and route levels. +// Validates behavior of request_headers_to_add at router, vhost, and route action levels. TEST(RouteMatcherTest, TestAddRemoveRequestHeaders) { std::string json = R"EOF( { @@ -552,14 +552,14 @@ TEST(RouteMatcherTest, TestAddRemoveRequestHeaders) { "request_headers_to_add": [ {"key": "x-global-header1", "value": "route-override"}, {"key": "x-vhost-header1", "value": "route-override"}, - {"key": "x-route-header", "value": "route-new_endpoint"} + {"key": "x-route-action-header", "value": "route-new_endpoint"} ] }, { "path": "/", "cluster": "root_www2", "request_headers_to_add": [ - {"key": "x-route-header", "value": "route-allpath"} + {"key": "x-route-action-header", "value": "route-allpath"} ] }, { @@ -579,7 +579,7 @@ TEST(RouteMatcherTest, TestAddRemoveRequestHeaders) { "prefix": "/", "cluster": "www2_staging", "request_headers_to_add": [ - {"key": "x-route-header", "value": "route-allprefix"} + {"key": "x-route-action-header", "value": "route-allprefix"} ] } ] @@ -629,7 +629,7 @@ TEST(RouteMatcherTest, TestAddRemoveRequestHeaders) { route->finalizeRequestHeaders(headers, request_info, true); EXPECT_EQ("route-override", headers.get_("x-global-header1")); EXPECT_EQ("route-override", headers.get_("x-vhost-header1")); - EXPECT_EQ("route-new_endpoint", headers.get_("x-route-header")); + EXPECT_EQ("route-new_endpoint", headers.get_("x-route-action-header")); } // Multiple routes can have same route-level headers with different values. @@ -639,7 +639,7 @@ TEST(RouteMatcherTest, TestAddRemoveRequestHeaders) { route->finalizeRequestHeaders(headers, request_info, true); EXPECT_EQ("vhost-override", headers.get_("x-global-header1")); EXPECT_EQ("vhost1-www2", headers.get_("x-vhost-header1")); - EXPECT_EQ("route-allpath", headers.get_("x-route-header")); + EXPECT_EQ("route-allpath", headers.get_("x-route-action-header")); } // Multiple virtual hosts can have same virtual host level headers with different values. @@ -649,7 +649,7 @@ TEST(RouteMatcherTest, TestAddRemoveRequestHeaders) { route->finalizeRequestHeaders(headers, request_info, true); EXPECT_EQ("global1", headers.get_("x-global-header1")); EXPECT_EQ("vhost1-www2_staging", headers.get_("x-vhost-header1")); - EXPECT_EQ("route-allprefix", headers.get_("x-route-header")); + EXPECT_EQ("route-allprefix", headers.get_("x-route-action-header")); } // Global headers. @@ -662,8 +662,8 @@ TEST(RouteMatcherTest, TestAddRemoveRequestHeaders) { } } -// Validates behavior of request_headers_to_add at router, vhost, and route levels when append -// is disabled. +// Validates behavior of request_headers_to_add at router, vhost, route, and route action levels +// when append is disabled. TEST(RouteMatcherTest, TestRequestHeadersToAddWithAppendFalse) { std::string yaml = R"EOF( name: foo @@ -681,20 +681,36 @@ name: foo append: false routes: - match: { prefix: "/endpoint" } + request_headers_to_add: + - header: + key: x-global-header + value: route-endpoint + append: false + - header: + key: x-vhost-header + value: route-endpoint + append: false + - header: + key: x-route-header + value: route-endpoint + append: false route: cluster: www2 request_headers_to_add: - header: key: x-global-header - value: route-endpoint + value: route-action-endpoint append: false - header: key: x-vhost-header - value: route-endpoint + value: route-action-endpoint append: false - header: key: x-route-header - value: route-endpoint + value: route-action-endpoint + - header: + key: x-route-action-header + value: route-action-endpoint append: false - match: { prefix: "/" } route: { cluster: www2 } @@ -714,7 +730,7 @@ name: foo // Request header manipulation testing. { - // Global and virtual host override route. + // Global and virtual host override route, route overrides route action. { Http::TestHeaderMapImpl headers = genHeaders("www.lyft.com", "/endpoint", "GET"); const RouteEntry* route = config.route(headers, 0)->routeEntry(); @@ -722,6 +738,7 @@ name: foo EXPECT_EQ("global", headers.get_("x-global-header")); EXPECT_EQ("vhost-www2", headers.get_("x-vhost-header")); EXPECT_EQ("route-endpoint", headers.get_("x-route-header")); + EXPECT_EQ("route-action-endpoint", headers.get_("x-route-action-header")); } // Global overrides virtual host. @@ -736,7 +753,7 @@ name: foo } // Validates behavior of response_headers_to_add and response_headers_to_remove at router, vhost, -// and route levels. +// route, and route action levels. TEST(RouteMatcherTest, TestAddRemoveResponseHeaders) { std::string yaml = R"EOF( name: foo @@ -753,6 +770,10 @@ name: foo response_headers_to_remove: ["x-vhost-remove"] routes: - match: { prefix: "/new_endpoint" } + response_headers_to_add: + - header: + key: x-route-header + value: route-override route: prefix_rewrite: "/api/new_endpoint" cluster: www2 @@ -764,14 +785,14 @@ name: foo key: x-vhost-header1 value: route-override - header: - key: x-route-header + key: x-route-action-header value: route-new_endpoint - match: { path: "/" } route: cluster: root_www2 response_headers_to_add: - header: - key: x-route-header + key: x-route-action-header value: route-allpath response_headers_to_remove: ["x-route-remove"] - match: { prefix: "/" } @@ -788,7 +809,7 @@ name: foo cluster: www2_staging response_headers_to_add: - header: - key: x-route-header + key: x-route-action-header value: route-allprefix - name: default domains: ["*"] @@ -817,7 +838,8 @@ response_headers_to_remove: ["x-global-remove"] route->finalizeResponseHeaders(headers, request_info); EXPECT_EQ("route-override", headers.get_("x-global-header1")); EXPECT_EQ("route-override", headers.get_("x-vhost-header1")); - EXPECT_EQ("route-new_endpoint", headers.get_("x-route-header")); + EXPECT_EQ("route-new_endpoint", headers.get_("x-route-action-header")); + EXPECT_EQ("route-override", headers.get_("x-route-header")); } // Multiple routes can have same route-level headers with different values. @@ -828,7 +850,7 @@ response_headers_to_remove: ["x-global-remove"] route->finalizeResponseHeaders(headers, request_info); EXPECT_EQ("vhost-override", headers.get_("x-global-header1")); EXPECT_EQ("vhost1-www2", headers.get_("x-vhost-header1")); - EXPECT_EQ("route-allpath", headers.get_("x-route-header")); + EXPECT_EQ("route-allpath", headers.get_("x-route-action-header")); } // Multiple virtual hosts can have same virtual host level headers with different values. @@ -839,7 +861,7 @@ response_headers_to_remove: ["x-global-remove"] route->finalizeResponseHeaders(headers, request_info); EXPECT_EQ("global1", headers.get_("x-global-header1")); EXPECT_EQ("vhost1-www2_staging", headers.get_("x-vhost-header1")); - EXPECT_EQ("route-allprefix", headers.get_("x-route-header")); + EXPECT_EQ("route-allprefix", headers.get_("x-route-action-header")); } // Global headers.