diff --git a/api/envoy/api/v2/cluster.proto b/api/envoy/api/v2/cluster.proto index 182afc8c521b..fab95f71b763 100644 --- a/api/envoy/api/v2/cluster.proto +++ b/api/envoy/api/v2/cluster.proto @@ -352,6 +352,10 @@ message Cluster { // This header isn't sanitized by default, so enabling this feature allows HTTP clients to // route traffic to arbitrary hosts and/or ports, which may have serious security // consequences. + // + // .. note:: + // + // If the header appears multiple times only the first value is used. bool use_http_header = 1; } diff --git a/api/envoy/api/v2/route/route_components.proto b/api/envoy/api/v2/route/route_components.proto index 339c7bcbc53a..c1e84a5618a7 100644 --- a/api/envoy/api/v2/route/route_components.proto +++ b/api/envoy/api/v2/route/route_components.proto @@ -756,6 +756,10 @@ message RouteAction { // // Internally, Envoy always uses the HTTP/2 *:authority* header to represent the HTTP/1 // *Host* header. Thus, if attempting to match on *Host*, match on *:authority* instead. + // + // .. note:: + // + // If the header appears multiple times only the first value is used. string cluster_header = 2 [(validate.rules).string = {min_bytes: 1 well_known_regex: HTTP_HEADER_NAME strict: false}]; @@ -866,6 +870,10 @@ message RouteAction { // // Pay attention to the potential security implications of using this option. Provided header // must come from trusted source. + // + // .. note:: + // + // If the header appears multiple times only the first value is used. string auto_host_rewrite_header = 29 [ (validate.rules).string = {well_known_regex: HTTP_HEADER_NAME strict: false}, (udpa.annotations.field_migrate).rename = "host_rewrite_header" diff --git a/api/envoy/config/cluster/v3/cluster.proto b/api/envoy/config/cluster/v3/cluster.proto index 10edef375f25..8e039a1f16fe 100644 --- a/api/envoy/config/cluster/v3/cluster.proto +++ b/api/envoy/config/cluster/v3/cluster.proto @@ -436,6 +436,10 @@ message Cluster { // This header isn't sanitized by default, so enabling this feature allows HTTP clients to // route traffic to arbitrary hosts and/or ports, which may have serious security // consequences. + // + // .. note:: + // + // If the header appears multiple times only the first value is used. bool use_http_header = 1; } diff --git a/api/envoy/config/cluster/v4alpha/cluster.proto b/api/envoy/config/cluster/v4alpha/cluster.proto index 35117aba77fd..0ad15668e6cf 100644 --- a/api/envoy/config/cluster/v4alpha/cluster.proto +++ b/api/envoy/config/cluster/v4alpha/cluster.proto @@ -442,6 +442,10 @@ message Cluster { // This header isn't sanitized by default, so enabling this feature allows HTTP clients to // route traffic to arbitrary hosts and/or ports, which may have serious security // consequences. + // + // .. note:: + // + // If the header appears multiple times only the first value is used. bool use_http_header = 1; } diff --git a/api/envoy/config/filter/http/dynamic_forward_proxy/v2alpha/dynamic_forward_proxy.proto b/api/envoy/config/filter/http/dynamic_forward_proxy/v2alpha/dynamic_forward_proxy.proto index 29aa8380191b..436bb6bf4616 100644 --- a/api/envoy/config/filter/http/dynamic_forward_proxy/v2alpha/dynamic_forward_proxy.proto +++ b/api/envoy/config/filter/http/dynamic_forward_proxy/v2alpha/dynamic_forward_proxy.proto @@ -51,6 +51,10 @@ message PerRouteConfig { // :ref:`HCM host rewrite header ` // given that the value set here would be used for DNS lookups whereas the value set in the HCM // would be used for host header forwarding which is not the desired outcome. + // + // .. note:: + // + // If the header appears multiple times only the first value is used. string auto_host_rewrite_header = 2 [(udpa.annotations.field_migrate).rename = "host_rewrite_header"]; } 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 06b13acb2f63..c05032df21a4 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 @@ -586,6 +586,10 @@ message ScopedRoutes { } // The name of the header field to extract the value from. + // + // .. note:: + // + // If the header appears multiple times only the first value is used. string name = 1 [(validate.rules).string = {min_bytes: 1}]; // The element separator (e.g., ';' separates 'a;b;c;d'). diff --git a/api/envoy/config/route/v3/route_components.proto b/api/envoy/config/route/v3/route_components.proto index 4555c9325515..407f285310a5 100644 --- a/api/envoy/config/route/v3/route_components.proto +++ b/api/envoy/config/route/v3/route_components.proto @@ -809,6 +809,10 @@ message RouteAction { // // Internally, Envoy always uses the HTTP/2 *:authority* header to represent the HTTP/1 // *Host* header. Thus, if attempting to match on *Host*, match on *:authority* instead. + // + // .. note:: + // + // If the header appears multiple times only the first value is used. string cluster_header = 2 [(validate.rules).string = {min_len: 1 well_known_regex: HTTP_HEADER_NAME strict: false}]; @@ -917,6 +921,10 @@ message RouteAction { // // Pay attention to the potential security implications of using this option. Provided header // must come from trusted source. + // + // .. note:: + // + // If the header appears multiple times only the first value is used. string host_rewrite_header = 29 [(validate.rules).string = {well_known_regex: HTTP_HEADER_NAME strict: false}]; @@ -1146,9 +1154,15 @@ message RetryPolicy { } message ResetHeader { + // The name of the reset header. + // + // .. note:: + // + // If the header appears multiple times only the first value is used. string name = 1 [(validate.rules).string = {min_len: 1 well_known_regex: HTTP_HEADER_NAME strict: false}]; + // The format of the reset header. ResetHeaderFormat format = 2 [(validate.rules).enum = {defined_only: true}]; } diff --git a/api/envoy/config/route/v4alpha/route_components.proto b/api/envoy/config/route/v4alpha/route_components.proto index c0bd5bac8db9..766d64ebedee 100644 --- a/api/envoy/config/route/v4alpha/route_components.proto +++ b/api/envoy/config/route/v4alpha/route_components.proto @@ -809,6 +809,10 @@ message RouteAction { // // Internally, Envoy always uses the HTTP/2 *:authority* header to represent the HTTP/1 // *Host* header. Thus, if attempting to match on *Host*, match on *:authority* instead. + // + // .. note:: + // + // If the header appears multiple times only the first value is used. string cluster_header = 2 [(validate.rules).string = {min_len: 1 well_known_regex: HTTP_HEADER_NAME strict: false}]; @@ -917,6 +921,10 @@ message RouteAction { // // Pay attention to the potential security implications of using this option. Provided header // must come from trusted source. + // + // .. note:: + // + // If the header appears multiple times only the first value is used. string host_rewrite_header = 29 [(validate.rules).string = {well_known_regex: HTTP_HEADER_NAME strict: false}]; @@ -1091,9 +1099,15 @@ message RetryPolicy { option (udpa.annotations.versioning).previous_message_type = "envoy.config.route.v3.RetryPolicy.ResetHeader"; + // The name of the reset header. + // + // .. note:: + // + // If the header appears multiple times only the first value is used. string name = 1 [(validate.rules).string = {min_len: 1 well_known_regex: HTTP_HEADER_NAME strict: false}]; + // The format of the reset header. ResetHeaderFormat format = 2 [(validate.rules).enum = {defined_only: true}]; } diff --git a/api/envoy/extensions/filters/http/dynamic_forward_proxy/v3/dynamic_forward_proxy.proto b/api/envoy/extensions/filters/http/dynamic_forward_proxy/v3/dynamic_forward_proxy.proto index b8a2525dbf54..70dd21a324b3 100644 --- a/api/envoy/extensions/filters/http/dynamic_forward_proxy/v3/dynamic_forward_proxy.proto +++ b/api/envoy/extensions/filters/http/dynamic_forward_proxy/v3/dynamic_forward_proxy.proto @@ -55,6 +55,10 @@ message PerRouteConfig { // :ref:`HCM host rewrite header ` // given that the value set here would be used for DNS lookups whereas the value set in the HCM // would be used for host header forwarding which is not the desired outcome. + // + // .. note:: + // + // If the header appears multiple times only the first value is used. string host_rewrite_header = 2; } } diff --git a/api/envoy/extensions/filters/network/http_connection_manager/v3/http_connection_manager.proto b/api/envoy/extensions/filters/network/http_connection_manager/v3/http_connection_manager.proto index 09f4771a60d9..a4c115c68da0 100644 --- a/api/envoy/extensions/filters/network/http_connection_manager/v3/http_connection_manager.proto +++ b/api/envoy/extensions/filters/network/http_connection_manager/v3/http_connection_manager.proto @@ -725,6 +725,10 @@ message ScopedRoutes { } // The name of the header field to extract the value from. + // + // .. note:: + // + // If the header appears multiple times only the first value is used. string name = 1 [(validate.rules).string = {min_len: 1}]; // The element separator (e.g., ';' separates 'a;b;c;d'). diff --git a/api/envoy/extensions/filters/network/http_connection_manager/v4alpha/http_connection_manager.proto b/api/envoy/extensions/filters/network/http_connection_manager/v4alpha/http_connection_manager.proto index 2ef64b3f3a77..ceb7f4a65a1f 100644 --- a/api/envoy/extensions/filters/network/http_connection_manager/v4alpha/http_connection_manager.proto +++ b/api/envoy/extensions/filters/network/http_connection_manager/v4alpha/http_connection_manager.proto @@ -730,6 +730,10 @@ message ScopedRoutes { } // The name of the header field to extract the value from. + // + // .. note:: + // + // If the header appears multiple times only the first value is used. string name = 1 [(validate.rules).string = {min_len: 1}]; // The element separator (e.g., ';' separates 'a;b;c;d'). diff --git a/ci/filter_example_setup.sh b/ci/filter_example_setup.sh index 0fd954bf2319..774464f15a7c 100644 --- a/ci/filter_example_setup.sh +++ b/ci/filter_example_setup.sh @@ -5,7 +5,7 @@ set -e # This is the hash on https://github.com/envoyproxy/envoy-filter-example.git we pin to. -ENVOY_FILTER_EXAMPLE_GITSHA="493e2e5bee10bbed1c3c097e09d83d7f672a9f2e" +ENVOY_FILTER_EXAMPLE_GITSHA="bebd0b2422ea7739905f1793565681d7266491e6" ENVOY_FILTER_EXAMPLE_SRCDIR="${BUILD_DIR}/envoy-filter-example" # shellcheck disable=SC2034 diff --git a/docs/root/configuration/http/http_filters/fault_filter.rst b/docs/root/configuration/http/http_filters/fault_filter.rst index 62b9cd9e28c8..2dbd48c58846 100644 --- a/docs/root/configuration/http/http_filters/fault_filter.rst +++ b/docs/root/configuration/http/http_filters/fault_filter.rst @@ -38,7 +38,7 @@ fault configuration. The currently supported header controls are: x-envoy-fault-abort-request HTTP status code to abort a request with. The header value should be an integer that specifies - the HTTP status code to return in response to a request and must be in the range [200, 600). + the HTTP status code to return in response to a request and must be in the range [200, 600). In order for the header to work, :ref:`header_abort ` needs to be set. @@ -47,8 +47,8 @@ x-envoy-fault-abort-grpc-request the gRPC status code to return in response to a request. Its value range is [0, UInt32.Max] instead of [0, 16] to allow testing even not well-defined gRPC status codes. When this header is set, the HTTP response status code will be set to 200. In order for the header to work, :ref:`header_abort - ` needs to be set. If both - *x-envoy-fault-abort-request* and *x-envoy-fault-abort-grpc-request* headers are set then + ` needs to be set. If both + *x-envoy-fault-abort-request* and *x-envoy-fault-abort-grpc-request* headers are set then *x-envoy-fault-abort-grpc-request* header will be **ignored** and fault response http status code will be set to *x-envoy-fault-abort-request* header value. @@ -105,6 +105,10 @@ x-envoy-fault-throughput-response-percentage ` setting to limit the maximum concurrent faults that can be active at any given time. +.. note:: + + If the headers appear multiple times only the first value is used. + The following is an example configuration that enables header control for both of the above options: diff --git a/generated_api_shadow/envoy/api/v2/cluster.proto b/generated_api_shadow/envoy/api/v2/cluster.proto index 182afc8c521b..fab95f71b763 100644 --- a/generated_api_shadow/envoy/api/v2/cluster.proto +++ b/generated_api_shadow/envoy/api/v2/cluster.proto @@ -352,6 +352,10 @@ message Cluster { // This header isn't sanitized by default, so enabling this feature allows HTTP clients to // route traffic to arbitrary hosts and/or ports, which may have serious security // consequences. + // + // .. note:: + // + // If the header appears multiple times only the first value is used. bool use_http_header = 1; } diff --git a/generated_api_shadow/envoy/api/v2/route/route_components.proto b/generated_api_shadow/envoy/api/v2/route/route_components.proto index 339c7bcbc53a..c1e84a5618a7 100644 --- a/generated_api_shadow/envoy/api/v2/route/route_components.proto +++ b/generated_api_shadow/envoy/api/v2/route/route_components.proto @@ -756,6 +756,10 @@ message RouteAction { // // Internally, Envoy always uses the HTTP/2 *:authority* header to represent the HTTP/1 // *Host* header. Thus, if attempting to match on *Host*, match on *:authority* instead. + // + // .. note:: + // + // If the header appears multiple times only the first value is used. string cluster_header = 2 [(validate.rules).string = {min_bytes: 1 well_known_regex: HTTP_HEADER_NAME strict: false}]; @@ -866,6 +870,10 @@ message RouteAction { // // Pay attention to the potential security implications of using this option. Provided header // must come from trusted source. + // + // .. note:: + // + // If the header appears multiple times only the first value is used. string auto_host_rewrite_header = 29 [ (validate.rules).string = {well_known_regex: HTTP_HEADER_NAME strict: false}, (udpa.annotations.field_migrate).rename = "host_rewrite_header" diff --git a/generated_api_shadow/envoy/config/cluster/v3/cluster.proto b/generated_api_shadow/envoy/config/cluster/v3/cluster.proto index 481266cba383..bc39aaa8799e 100644 --- a/generated_api_shadow/envoy/config/cluster/v3/cluster.proto +++ b/generated_api_shadow/envoy/config/cluster/v3/cluster.proto @@ -436,6 +436,10 @@ message Cluster { // This header isn't sanitized by default, so enabling this feature allows HTTP clients to // route traffic to arbitrary hosts and/or ports, which may have serious security // consequences. + // + // .. note:: + // + // If the header appears multiple times only the first value is used. bool use_http_header = 1; } diff --git a/generated_api_shadow/envoy/config/cluster/v4alpha/cluster.proto b/generated_api_shadow/envoy/config/cluster/v4alpha/cluster.proto index d0883e9c4629..d83b54cabeb4 100644 --- a/generated_api_shadow/envoy/config/cluster/v4alpha/cluster.proto +++ b/generated_api_shadow/envoy/config/cluster/v4alpha/cluster.proto @@ -442,6 +442,10 @@ message Cluster { // This header isn't sanitized by default, so enabling this feature allows HTTP clients to // route traffic to arbitrary hosts and/or ports, which may have serious security // consequences. + // + // .. note:: + // + // If the header appears multiple times only the first value is used. bool use_http_header = 1; } diff --git a/generated_api_shadow/envoy/config/filter/http/dynamic_forward_proxy/v2alpha/dynamic_forward_proxy.proto b/generated_api_shadow/envoy/config/filter/http/dynamic_forward_proxy/v2alpha/dynamic_forward_proxy.proto index 29aa8380191b..436bb6bf4616 100644 --- a/generated_api_shadow/envoy/config/filter/http/dynamic_forward_proxy/v2alpha/dynamic_forward_proxy.proto +++ b/generated_api_shadow/envoy/config/filter/http/dynamic_forward_proxy/v2alpha/dynamic_forward_proxy.proto @@ -51,6 +51,10 @@ message PerRouteConfig { // :ref:`HCM host rewrite header ` // given that the value set here would be used for DNS lookups whereas the value set in the HCM // would be used for host header forwarding which is not the desired outcome. + // + // .. note:: + // + // If the header appears multiple times only the first value is used. string auto_host_rewrite_header = 2 [(udpa.annotations.field_migrate).rename = "host_rewrite_header"]; } diff --git a/generated_api_shadow/envoy/config/filter/network/http_connection_manager/v2/http_connection_manager.proto b/generated_api_shadow/envoy/config/filter/network/http_connection_manager/v2/http_connection_manager.proto index 06b13acb2f63..c05032df21a4 100644 --- a/generated_api_shadow/envoy/config/filter/network/http_connection_manager/v2/http_connection_manager.proto +++ b/generated_api_shadow/envoy/config/filter/network/http_connection_manager/v2/http_connection_manager.proto @@ -586,6 +586,10 @@ message ScopedRoutes { } // The name of the header field to extract the value from. + // + // .. note:: + // + // If the header appears multiple times only the first value is used. string name = 1 [(validate.rules).string = {min_bytes: 1}]; // The element separator (e.g., ';' separates 'a;b;c;d'). diff --git a/generated_api_shadow/envoy/config/route/v3/route_components.proto b/generated_api_shadow/envoy/config/route/v3/route_components.proto index a3b918711e8a..a3a823cafe44 100644 --- a/generated_api_shadow/envoy/config/route/v3/route_components.proto +++ b/generated_api_shadow/envoy/config/route/v3/route_components.proto @@ -818,6 +818,10 @@ message RouteAction { // // Internally, Envoy always uses the HTTP/2 *:authority* header to represent the HTTP/1 // *Host* header. Thus, if attempting to match on *Host*, match on *:authority* instead. + // + // .. note:: + // + // If the header appears multiple times only the first value is used. string cluster_header = 2 [(validate.rules).string = {min_len: 1 well_known_regex: HTTP_HEADER_NAME strict: false}]; @@ -926,6 +930,10 @@ message RouteAction { // // Pay attention to the potential security implications of using this option. Provided header // must come from trusted source. + // + // .. note:: + // + // If the header appears multiple times only the first value is used. string host_rewrite_header = 29 [(validate.rules).string = {well_known_regex: HTTP_HEADER_NAME strict: false}]; @@ -1153,9 +1161,15 @@ message RetryPolicy { } message ResetHeader { + // The name of the reset header. + // + // .. note:: + // + // If the header appears multiple times only the first value is used. string name = 1 [(validate.rules).string = {min_len: 1 well_known_regex: HTTP_HEADER_NAME strict: false}]; + // The format of the reset header. ResetHeaderFormat format = 2 [(validate.rules).enum = {defined_only: true}]; } diff --git a/generated_api_shadow/envoy/config/route/v4alpha/route_components.proto b/generated_api_shadow/envoy/config/route/v4alpha/route_components.proto index 6608c7f96a7d..4d4a93eebe60 100644 --- a/generated_api_shadow/envoy/config/route/v4alpha/route_components.proto +++ b/generated_api_shadow/envoy/config/route/v4alpha/route_components.proto @@ -817,6 +817,10 @@ message RouteAction { // // Internally, Envoy always uses the HTTP/2 *:authority* header to represent the HTTP/1 // *Host* header. Thus, if attempting to match on *Host*, match on *:authority* instead. + // + // .. note:: + // + // If the header appears multiple times only the first value is used. string cluster_header = 2 [(validate.rules).string = {min_len: 1 well_known_regex: HTTP_HEADER_NAME strict: false}]; @@ -925,6 +929,10 @@ message RouteAction { // // Pay attention to the potential security implications of using this option. Provided header // must come from trusted source. + // + // .. note:: + // + // If the header appears multiple times only the first value is used. string host_rewrite_header = 29 [(validate.rules).string = {well_known_regex: HTTP_HEADER_NAME strict: false}]; @@ -1158,9 +1166,15 @@ message RetryPolicy { option (udpa.annotations.versioning).previous_message_type = "envoy.config.route.v3.RetryPolicy.ResetHeader"; + // The name of the reset header. + // + // .. note:: + // + // If the header appears multiple times only the first value is used. string name = 1 [(validate.rules).string = {min_len: 1 well_known_regex: HTTP_HEADER_NAME strict: false}]; + // The format of the reset header. ResetHeaderFormat format = 2 [(validate.rules).enum = {defined_only: true}]; } diff --git a/generated_api_shadow/envoy/extensions/filters/http/dynamic_forward_proxy/v3/dynamic_forward_proxy.proto b/generated_api_shadow/envoy/extensions/filters/http/dynamic_forward_proxy/v3/dynamic_forward_proxy.proto index b8a2525dbf54..70dd21a324b3 100644 --- a/generated_api_shadow/envoy/extensions/filters/http/dynamic_forward_proxy/v3/dynamic_forward_proxy.proto +++ b/generated_api_shadow/envoy/extensions/filters/http/dynamic_forward_proxy/v3/dynamic_forward_proxy.proto @@ -55,6 +55,10 @@ message PerRouteConfig { // :ref:`HCM host rewrite header ` // given that the value set here would be used for DNS lookups whereas the value set in the HCM // would be used for host header forwarding which is not the desired outcome. + // + // .. note:: + // + // If the header appears multiple times only the first value is used. string host_rewrite_header = 2; } } diff --git a/generated_api_shadow/envoy/extensions/filters/network/http_connection_manager/v3/http_connection_manager.proto b/generated_api_shadow/envoy/extensions/filters/network/http_connection_manager/v3/http_connection_manager.proto index a56712c4b9d0..d26ce2ffee96 100644 --- a/generated_api_shadow/envoy/extensions/filters/network/http_connection_manager/v3/http_connection_manager.proto +++ b/generated_api_shadow/envoy/extensions/filters/network/http_connection_manager/v3/http_connection_manager.proto @@ -730,6 +730,10 @@ message ScopedRoutes { } // The name of the header field to extract the value from. + // + // .. note:: + // + // If the header appears multiple times only the first value is used. string name = 1 [(validate.rules).string = {min_len: 1}]; // The element separator (e.g., ';' separates 'a;b;c;d'). diff --git a/generated_api_shadow/envoy/extensions/filters/network/http_connection_manager/v4alpha/http_connection_manager.proto b/generated_api_shadow/envoy/extensions/filters/network/http_connection_manager/v4alpha/http_connection_manager.proto index 2ef64b3f3a77..ceb7f4a65a1f 100644 --- a/generated_api_shadow/envoy/extensions/filters/network/http_connection_manager/v4alpha/http_connection_manager.proto +++ b/generated_api_shadow/envoy/extensions/filters/network/http_connection_manager/v4alpha/http_connection_manager.proto @@ -730,6 +730,10 @@ message ScopedRoutes { } // The name of the header field to extract the value from. + // + // .. note:: + // + // If the header appears multiple times only the first value is used. string name = 1 [(validate.rules).string = {min_len: 1}]; // The element separator (e.g., ';' separates 'a;b;c;d'). diff --git a/include/envoy/http/header_map.h b/include/envoy/http/header_map.h index daa5bbeb1988..26b6bdf926b6 100644 --- a/include/envoy/http/header_map.h +++ b/include/envoy/http/header_map.h @@ -506,14 +506,7 @@ class HeaderMap { virtual uint64_t byteSize() const PURE; /** - * Get a header by key. - * @param key supplies the header key. - * @return the header entry if it exists otherwise nullptr. - */ - virtual const HeaderEntry* get(const LowerCaseString& key) const PURE; - - /** - * This is a wrapper for the return result from getAll(). It avoids a copy when translating from + * This is a wrapper for the return result from get(). It avoids a copy when translating from * non-const HeaderEntry to const HeaderEntry and only provides const access to the result. */ using NonConstGetResult = absl::InlinedVector; @@ -536,7 +529,7 @@ class HeaderMap { * @param key supplies the header key. * @return all header entries matching the key. */ - virtual GetResult getAll(const LowerCaseString& key) const PURE; + virtual GetResult get(const LowerCaseString& key) const PURE; // aliases to make iterate() and iterateReverse() callbacks easier to read enum class Iterate { Continue, Break }; diff --git a/source/common/formatter/substitution_formatter.cc b/source/common/formatter/substitution_formatter.cc index abb5caa100be..9b121db96803 100644 --- a/source/common/formatter/substitution_formatter.cc +++ b/source/common/formatter/substitution_formatter.cc @@ -863,13 +863,15 @@ HeaderFormatter::HeaderFormatter(const std::string& main_header, : main_header_(main_header), alternative_header_(alternative_header), max_length_(max_length) {} const Http::HeaderEntry* HeaderFormatter::findHeader(const Http::HeaderMap& headers) const { - const Http::HeaderEntry* header = headers.get(main_header_); + const auto header = headers.get(main_header_); - if (!header && !alternative_header_.get().empty()) { - return headers.get(alternative_header_); + if (header.empty() && !alternative_header_.get().empty()) { + const auto alternate_header = headers.get(alternative_header_); + // TODO(https://github.com/envoyproxy/envoy/issues/13454): Potentially log all header values. + return alternate_header.empty() ? nullptr : alternate_header[0]; } - return header; + return header.empty() ? nullptr : header[0]; } absl::optional HeaderFormatter::format(const Http::HeaderMap& headers) const { diff --git a/source/common/grpc/common.cc b/source/common/grpc/common.cc index 51196a8a8fac..8b7551d8bea2 100644 --- a/source/common/grpc/common.cc +++ b/source/common/grpc/common.cc @@ -103,13 +103,14 @@ std::string Common::getGrpcMessage(const Http::ResponseHeaderOrTrailerMap& trail absl::optional Common::getGrpcStatusDetailsBin(const Http::HeaderMap& trailers) { - const Http::HeaderEntry* details_header = trailers.get(Http::Headers::get().GrpcStatusDetailsBin); - if (!details_header) { + const auto details_header = trailers.get(Http::Headers::get().GrpcStatusDetailsBin); + if (details_header.empty()) { return absl::nullopt; } // Some implementations use non-padded base64 encoding for grpc-status-details-bin. - auto decoded_value = Base64::decodeWithoutPadding(details_header->value().getStringView()); + // This is effectively a trusted header so using the first value is fine. + auto decoded_value = Base64::decodeWithoutPadding(details_header[0]->value().getStringView()); if (decoded_value.empty()) { return absl::nullopt; } diff --git a/source/common/http/hash_policy.cc b/source/common/http/hash_policy.cc index d00dbb99fed7..9fa0f6377fb0 100644 --- a/source/common/http/hash_policy.cc +++ b/source/common/http/hash_policy.cc @@ -39,13 +39,14 @@ class HeaderHashMethod : public HashMethodImplBase { const StreamInfo::FilterStateSharedPtr) const override { absl::optional hash; - const HeaderEntry* header = headers.get(header_name_); - if (header) { + // TODO(mattklein123): Potentially hash on all headers. + const auto header = headers.get(header_name_); + if (!header.empty()) { if (regex_rewrite_ != nullptr) { - hash = HashUtil::xxHash64(regex_rewrite_->replaceAll(header->value().getStringView(), + hash = HashUtil::xxHash64(regex_rewrite_->replaceAll(header[0]->value().getStringView(), regex_rewrite_substitution_)); } else { - hash = HashUtil::xxHash64(header->value().getStringView()); + hash = HashUtil::xxHash64(header[0]->value().getStringView()); } } return hash; diff --git a/source/common/http/header_map_impl.cc b/source/common/http/header_map_impl.cc index af82752b04c8..6a4c00e5663e 100644 --- a/source/common/http/header_map_impl.cc +++ b/source/common/http/header_map_impl.cc @@ -473,12 +473,7 @@ void HeaderMapImpl::verifyByteSizeInternalForTest() const { ASSERT(cached_byte_size_ == byte_size); } -const HeaderEntry* HeaderMapImpl::get(const LowerCaseString& key) const { - const auto result = getAll(key); - return result.empty() ? nullptr : result[0]; -} - -HeaderMap::GetResult HeaderMapImpl::getAll(const LowerCaseString& key) const { +HeaderMap::GetResult HeaderMapImpl::get(const LowerCaseString& key) const { return HeaderMap::GetResult(const_cast(this)->getExisting(key)); } diff --git a/source/common/http/header_map_impl.h b/source/common/http/header_map_impl.h index 6fa14e6b5d1d..375abeca3658 100644 --- a/source/common/http/header_map_impl.h +++ b/source/common/http/header_map_impl.h @@ -86,8 +86,7 @@ class HeaderMapImpl : NonCopyable { void setReferenceKey(const LowerCaseString& key, absl::string_view value); void setCopy(const LowerCaseString& key, absl::string_view value); uint64_t byteSize() const; - const HeaderEntry* get(const LowerCaseString& key) const; - HeaderMap::GetResult getAll(const LowerCaseString& key) const; + HeaderMap::GetResult get(const LowerCaseString& key) const; void iterate(HeaderMap::ConstIterateCb cb) const; void iterateReverse(HeaderMap::ConstIterateCb cb) const; void clear(); @@ -369,12 +368,9 @@ template class TypedHeaderMapImpl : public HeaderMapImpl, publ HeaderMapImpl::setCopy(key, value); } uint64_t byteSize() const override { return HeaderMapImpl::byteSize(); } - const HeaderEntry* get(const LowerCaseString& key) const override { + HeaderMap::GetResult get(const LowerCaseString& key) const override { return HeaderMapImpl::get(key); } - HeaderMap::GetResult getAll(const LowerCaseString& key) const override { - return HeaderMapImpl::getAll(key); - } void iterate(HeaderMap::ConstIterateCb cb) const override { HeaderMapImpl::iterate(cb); } void iterateReverse(HeaderMap::ConstIterateCb cb) const override { HeaderMapImpl::iterateReverse(cb); diff --git a/source/common/http/header_utility.cc b/source/common/http/header_utility.cc index 91f15b4aeb0d..3e030010de4f 100644 --- a/source/common/http/header_utility.cc +++ b/source/common/http/header_utility.cc @@ -80,17 +80,6 @@ HeaderUtility::HeaderData::HeaderData(const envoy::config::route::v3::HeaderMatc } } -void HeaderUtility::getAllOfHeader(const HeaderMap& headers, absl::string_view key, - std::vector& out) { - headers.iterate([key = LowerCaseString(std::string(key)), - &out](const HeaderEntry& header) -> HeaderMap::Iterate { - if (header.key() == key.get().c_str()) { - out.emplace_back(header.value().getStringView()); - } - return HeaderMap::Iterate::Continue; - }); -} - bool HeaderUtility::matchHeaders(const HeaderMap& request_headers, const std::vector& config_headers) { // No headers to match is considered a match. @@ -106,9 +95,10 @@ bool HeaderUtility::matchHeaders(const HeaderMap& request_headers, } HeaderUtility::GetAllOfHeaderAsStringResult -HeaderUtility::getAllOfHeaderAsString(const HeaderMap& headers, const Http::LowerCaseString& key) { +HeaderUtility::getAllOfHeaderAsString(const HeaderMap& headers, const Http::LowerCaseString& key, + absl::string_view separator) { GetAllOfHeaderAsStringResult result; - const auto header_value = headers.getAll(key); + const auto header_value = headers.get(key); if (header_value.empty()) { // Empty for clarity. Avoid handling the empty case in the block below if the runtime feature @@ -118,7 +108,7 @@ HeaderUtility::getAllOfHeaderAsString(const HeaderMap& headers, const Http::Lowe "envoy.reloadable_features.http_match_on_all_headers")) { result.result_ = header_value[0]->value().getStringView(); } else { - // In this case we concatenate all found headers using a ',' delimiter before performing the + // In this case we concatenate all found headers using a delimiter before performing the // final match. We use an InlinedVector of absl::string_view to invoke the optimized join // algorithm. This requires a copying phase before we invoke join. The 3 used as the inline // size has been arbitrarily chosen. @@ -128,7 +118,7 @@ HeaderUtility::getAllOfHeaderAsString(const HeaderMap& headers, const Http::Lowe for (size_t i = 0; i < header_value.size(); i++) { string_view_vector.push_back(header_value[i]->value().getStringView()); } - result.result_backing_string_ = absl::StrJoin(string_view_vector, ","); + result.result_backing_string_ = absl::StrJoin(string_view_vector, separator); } return result; diff --git a/source/common/http/header_utility.h b/source/common/http/header_utility.h index 73dbd2d4a953..0a1e23c46717 100644 --- a/source/common/http/header_utility.h +++ b/source/common/http/header_utility.h @@ -20,18 +20,6 @@ class HeaderUtility { public: enum class HeaderMatchType { Value, Regex, Range, Present, Prefix, Suffix, Contains }; - /** - * Get all instances of the header key specified, and return the values in the vector provided. - * - * This should not be used for inline headers, as it turns a constant time lookup into O(n). - * - * @param headers the headers to return keys from - * @param key the header key to return values for - * @param out the vector to return values in - */ - static void getAllOfHeader(const HeaderMap& headers, absl::string_view key, - std::vector& out); - /** * Get all header values as a single string. Multiple headers are concatenated with ','. */ @@ -59,7 +47,8 @@ class HeaderUtility { friend class HeaderUtility; }; static GetAllOfHeaderAsStringResult getAllOfHeaderAsString(const HeaderMap& headers, - const Http::LowerCaseString& key); + const Http::LowerCaseString& key, + absl::string_view separator = ","); // A HeaderData specifies one of exact value or regex or range element // to match in a request's header, specified in the header_match_type_ member. diff --git a/source/common/http/utility.cc b/source/common/http/utility.cc index 8869e6bb5a2a..d522d61e237a 100644 --- a/source/common/http/utility.cc +++ b/source/common/http/utility.cc @@ -645,7 +645,7 @@ bool Utility::sanitizeConnectionHeader(Http::RequestHeaderMap& headers) { bool keep_header = false; // Determine whether the nominated header contains invalid values - const HeaderEntry* nominated_header = nullptr; + HeaderMap::GetResult nominated_header; if (lcs_header_to_remove == Http::Headers::get().Connection) { // Remove the connection header from the nominated tokens if it's self nominated @@ -672,8 +672,10 @@ bool Utility::sanitizeConnectionHeader(Http::RequestHeaderMap& headers) { nominated_header = headers.get(lcs_header_to_remove); } - if (nominated_header) { - auto nominated_header_value_sv = nominated_header->value().getStringView(); + if (!nominated_header.empty()) { + // NOTE: The TE header is an inline header, so by definition if we operate on it there can + // only be a single value. In all other cases we remove the nominated header. + auto nominated_header_value_sv = nominated_header[0]->value().getStringView(); const bool is_te_header = (lcs_header_to_remove == Http::Headers::get().TE); @@ -684,6 +686,7 @@ bool Utility::sanitizeConnectionHeader(Http::RequestHeaderMap& headers) { } if (is_te_header) { + ASSERT(nominated_header.size() == 1); for (const auto& header_value : StringUtil::splitToken(nominated_header_value_sv, ",", false)) { diff --git a/source/common/router/config_impl.cc b/source/common/router/config_impl.cc index d7c42a29bba2..1e2c7680a262 100644 --- a/source/common/router/config_impl.cc +++ b/source/common/router/config_impl.cc @@ -550,9 +550,11 @@ void RouteEntryImplBase::finalizeRequestHeaders(Http::RequestHeaderMap& headers, if (!host_rewrite_.empty()) { headers.setHost(host_rewrite_); } else if (auto_host_rewrite_header_) { - const Http::HeaderEntry* header = headers.get(*auto_host_rewrite_header_); - if (header != nullptr) { - absl::string_view header_value = header->value().getStringView(); + const auto header = headers.get(*auto_host_rewrite_header_); + if (!header.empty()) { + // This is an implicitly untrusted header, so per the API documentation only the first + // value is used. + const absl::string_view header_value = header[0]->value().getStringView(); if (!header_value.empty()) { headers.setHost(header_value); } @@ -881,10 +883,12 @@ RouteConstSharedPtr RouteEntryImplBase::clusterEntry(const Http::HeaderMap& head return shared_from_this(); } else { ASSERT(!cluster_header_name_.get().empty()); - const Http::HeaderEntry* entry = headers.get(cluster_header_name_); + const auto entry = headers.get(cluster_header_name_); std::string final_cluster_name; - if (entry) { - final_cluster_name = std::string(entry->value().getStringView()); + if (!entry.empty()) { + // This is an implicitly untrusted header, so per the API documentation only the first + // value is used. + final_cluster_name = std::string(entry[0]->value().getStringView()); } // NOTE: Though we return a shared_ptr here, the current ownership model assumes that diff --git a/source/common/router/header_formatter.cc b/source/common/router/header_formatter.cc index 5cc898b1e841..a15e07ec374a 100644 --- a/source/common/router/header_formatter.cc +++ b/source/common/router/header_formatter.cc @@ -186,8 +186,11 @@ parseRequestHeader(absl::string_view param) { Http::LowerCaseString header_name{std::string(param)}; return [header_name](const Envoy::StreamInfo::StreamInfo& stream_info) -> std::string { if (const auto* request_headers = stream_info.getRequestHeaders()) { - if (const auto* entry = request_headers->get(header_name)) { - return std::string(entry->value().getStringView()); + const auto entry = request_headers->get(header_name); + if (!entry.empty()) { + // TODO(https://github.com/envoyproxy/envoy/issues/13454): Potentially use all header + // values. + return std::string(entry[0]->value().getStringView()); } } return std::string(); diff --git a/source/common/router/reset_header_parser.cc b/source/common/router/reset_header_parser.cc index f5d61e9ca714..6089dedd5b0c 100644 --- a/source/common/router/reset_header_parser.cc +++ b/source/common/router/reset_header_parser.cc @@ -27,13 +27,14 @@ ResetHeaderParserImpl::ResetHeaderParserImpl( absl::optional ResetHeaderParserImpl::parseInterval(TimeSource& time_source, const Http::HeaderMap& headers) const { - const Http::HeaderEntry* header = headers.get(name_); + const auto header = headers.get(name_); - if (header == nullptr) { + if (header.empty()) { return absl::nullopt; } - const auto& header_value = header->value().getStringView(); + // This is effectively a trusted header so per the API only using the first value is used. + const auto& header_value = header[0]->value().getStringView(); uint64_t num_seconds{}; switch (format_) { diff --git a/source/common/router/router_ratelimit.cc b/source/common/router/router_ratelimit.cc index 615b34412e85..c75d58b50d9b 100644 --- a/source/common/router/router_ratelimit.cc +++ b/source/common/router/router_ratelimit.cc @@ -67,16 +67,17 @@ bool RequestHeadersAction::populateDescriptor(const Router::RouteEntry&, const Http::HeaderMap& headers, const Network::Address::Instance&, const envoy::config::core::v3::Metadata*) const { - const Http::HeaderEntry* header_value = headers.get(header_name_); + const auto header_value = headers.get(header_name_); // If header is not present in the request and if skip_if_absent is true skip this descriptor, // while calling rate limiting service. If skip_if_absent is false, do not call rate limiting // service. - if (!header_value) { + if (header_value.empty()) { return skip_if_absent_; } + // TODO(https://github.com/envoyproxy/envoy/issues/13454): Potentially populate all header values. descriptor.entries_.push_back( - {descriptor_key_, std::string(header_value->value().getStringView())}); + {descriptor_key_, std::string(header_value[0]->value().getStringView())}); return true; } diff --git a/source/common/router/scoped_config_impl.cc b/source/common/router/scoped_config_impl.cc index ef8c7e612471..4c379e1b7a33 100644 --- a/source/common/router/scoped_config_impl.cc +++ b/source/common/router/scoped_config_impl.cc @@ -40,15 +40,17 @@ HeaderValueExtractorImpl::HeaderValueExtractorImpl( std::unique_ptr HeaderValueExtractorImpl::computeFragment(const Http::HeaderMap& headers) const { - const Envoy::Http::HeaderEntry* header_entry = + const auto header_entry = headers.get(Envoy::Http::LowerCaseString(header_value_extractor_config_.name())); - if (header_entry == nullptr) { + if (header_entry.empty()) { return nullptr; } - std::vector elements{header_entry->value().getStringView()}; + // This is an implicitly untrusted header, so per the API documentation only the first + // value is used. + std::vector elements{header_entry[0]->value().getStringView()}; if (header_value_extractor_config_.element_separator().length() > 0) { - elements = absl::StrSplit(header_entry->value().getStringView(), + elements = absl::StrSplit(header_entry[0]->value().getStringView(), header_value_extractor_config_.element_separator()); } switch (header_value_extractor_config_.extract_type_case()) { diff --git a/source/common/tracing/http_tracer_impl.cc b/source/common/tracing/http_tracer_impl.cc index 4e3cba7023d7..8f46c812af64 100644 --- a/source/common/tracing/http_tracer_impl.cc +++ b/source/common/tracing/http_tracer_impl.cc @@ -322,8 +322,9 @@ absl::string_view RequestHeaderCustomTag::value(const CustomTagContext& ctx) con if (!ctx.request_headers) { return default_value_; } - const Http::HeaderEntry* entry = ctx.request_headers->get(name_); - return entry ? entry->value().getStringView() : default_value_; + // TODO(https://github.com/envoyproxy/envoy/issues/13454): Potentially populate all header values. + const auto entry = ctx.request_headers->get(name_); + return !entry.empty() ? entry[0]->value().getStringView() : default_value_; } MetadataCustomTag::MetadataCustomTag(const std::string& tag, diff --git a/source/common/upstream/original_dst_cluster.cc b/source/common/upstream/original_dst_cluster.cc index a84193ce64cb..2f2eec5e98ef 100644 --- a/source/common/upstream/original_dst_cluster.cc +++ b/source/common/upstream/original_dst_cluster.cc @@ -84,13 +84,15 @@ Network::Address::InstanceConstSharedPtr OriginalDstCluster::LoadBalancer::requestOverrideHost(LoadBalancerContext* context) { Network::Address::InstanceConstSharedPtr request_host; const Http::HeaderMap* downstream_headers = context->downstreamHeaders(); - if (downstream_headers && - downstream_headers->get(Http::Headers::get().EnvoyOriginalDstHost) != nullptr) { - const std::string request_override_host( - downstream_headers->get(Http::Headers::get().EnvoyOriginalDstHost) - ->value() - .getStringView()); + Http::HeaderMap::GetResult override_header; + if (downstream_headers) { + override_header = downstream_headers->get(Http::Headers::get().EnvoyOriginalDstHost); + } + if (!override_header.empty()) { try { + // This is an implicitly untrusted header, so per the API documentation only the first + // value is used. + const std::string request_override_host(override_header[0]->value().getStringView()); request_host = Network::Utility::parseInternetAddressAndPort(request_override_host, false); ENVOY_LOG(debug, "Using request override host {}.", request_override_host); } catch (const Envoy::EnvoyException& e) { diff --git a/source/extensions/access_loggers/grpc/http_grpc_access_log_impl.cc b/source/extensions/access_loggers/grpc/http_grpc_access_log_impl.cc index 92bc5e38ee73..4d81f7b19477 100644 --- a/source/extensions/access_loggers/grpc/http_grpc_access_log_impl.cc +++ b/source/extensions/access_loggers/grpc/http_grpc_access_log_impl.cc @@ -115,9 +115,11 @@ void HttpGrpcAccessLog::emitLog(const Http::RequestHeaderMap& request_headers, auto* logged_headers = request_properties->mutable_request_headers(); for (const auto& header : request_headers_to_log_) { - const Http::HeaderEntry* entry = request_headers.get(header); - if (entry != nullptr) { - logged_headers->insert({header.get(), std::string(entry->value().getStringView())}); + const auto entry = request_headers.get(header); + if (!entry.empty()) { + // TODO(https://github.com/envoyproxy/envoy/issues/13454): Potentially log all header + // values. + logged_headers->insert({header.get(), std::string(entry[0]->value().getStringView())}); } } } @@ -136,9 +138,11 @@ void HttpGrpcAccessLog::emitLog(const Http::RequestHeaderMap& request_headers, auto* logged_headers = response_properties->mutable_response_headers(); for (const auto& header : response_headers_to_log_) { - const Http::HeaderEntry* entry = response_headers.get(header); - if (entry != nullptr) { - logged_headers->insert({header.get(), std::string(entry->value().getStringView())}); + const auto entry = response_headers.get(header); + if (!entry.empty()) { + // TODO(https://github.com/envoyproxy/envoy/issues/13454): Potentially log all header + // values. + logged_headers->insert({header.get(), std::string(entry[0]->value().getStringView())}); } } } @@ -147,9 +151,11 @@ void HttpGrpcAccessLog::emitLog(const Http::RequestHeaderMap& request_headers, auto* logged_headers = response_properties->mutable_response_trailers(); for (const auto& header : response_trailers_to_log_) { - const Http::HeaderEntry* entry = response_trailers.get(header); - if (entry != nullptr) { - logged_headers->insert({header.get(), std::string(entry->value().getStringView())}); + const auto entry = response_trailers.get(header); + if (!entry.empty()) { + // TODO(https://github.com/envoyproxy/envoy/issues/13454): Potentially log all header + // values. + logged_headers->insert({header.get(), std::string(entry[0]->value().getStringView())}); } } } diff --git a/source/extensions/common/wasm/context.cc b/source/extensions/common/wasm/context.cc index 4e308524d4b7..6ff15293fd92 100644 --- a/source/extensions/common/wasm/context.cc +++ b/source/extensions/common/wasm/context.cc @@ -696,8 +696,8 @@ WasmResult Context::getHeaderMapValue(WasmHeaderMapType type, absl::string_view return WasmResult::BadArgument; } const Http::LowerCaseString lower_key{std::string(key)}; - auto entry = map->get(lower_key); - if (!entry) { + const auto entry = map->get(lower_key); + if (entry.empty()) { if (wasm()->abiVersion() == proxy_wasm::AbiVersion::ProxyWasm_0_1_0) { *value = ""; return WasmResult::Ok; @@ -705,7 +705,9 @@ WasmResult Context::getHeaderMapValue(WasmHeaderMapType type, absl::string_view return WasmResult::NotFound; } } - *value = entry->value().getStringView(); + // TODO(kyessenov, PiotrSikora): This needs to either return a concatenated list of values, or + // the ABI needs to be changed to return multiple values. This is a potential security issue. + *value = entry[0]->value().getStringView(); return WasmResult::Ok; } diff --git a/source/extensions/filters/common/ext_authz/ext_authz_http_impl.cc b/source/extensions/filters/common/ext_authz/ext_authz_http_impl.cc index c8a9b6f1a870..e2e27ab6894d 100644 --- a/source/extensions/filters/common/ext_authz/ext_authz_http_impl.cc +++ b/source/extensions/filters/common/ext_authz/ext_authz_http_impl.cc @@ -301,7 +301,7 @@ ResponsePtr RawHttpClientImpl::toResponse(Http::ResponseMessagePtr message) { // headers_to_remove in a variable first. std::vector headers_to_remove; if (status_code == enumToInt(Http::Code::OK)) { - const auto& get_result = message->headers().getAll(storage_header_name); + const auto& get_result = message->headers().get(storage_header_name); for (size_t i = 0; i < get_result.size(); ++i) { const Http::HeaderEntry* entry = get_result[i]; if (entry != nullptr) { diff --git a/source/extensions/filters/common/fault/fault_config.cc b/source/extensions/filters/common/fault/fault_config.cc index 4053cc0b9006..db7f6028152c 100644 --- a/source/extensions/filters/common/fault/fault_config.cc +++ b/source/extensions/filters/common/fault/fault_config.cc @@ -18,12 +18,14 @@ HeaderPercentageProvider::percentage(const Http::RequestHeaderMap* request_heade return percentage_; } const auto header = request_headers->get(header_name_); - if (header == nullptr) { + if (header.empty()) { return percentage_; } uint32_t header_numerator; - if (!absl::SimpleAtoi(header->value().getStringView(), &header_numerator)) { + // This is an implicitly untrusted header, so per the API documentation only the first + // value is used. + if (!absl::SimpleAtoi(header[0]->value().getStringView(), &header_numerator)) { return percentage_; } @@ -58,12 +60,14 @@ absl::optional FaultAbortConfig::HeaderAbortProvider::httpStatusCode const Http::RequestHeaderMap* request_headers) const { absl::optional ret = absl::nullopt; auto header = request_headers->get(Filters::Common::Fault::HeaderNames::get().AbortRequest); - if (header == nullptr) { + if (header.empty()) { return ret; } uint64_t code; - if (!absl::SimpleAtoi(header->value().getStringView(), &code)) { + // This is an implicitly untrusted header, so per the API documentation only the first + // value is used. + if (!absl::SimpleAtoi(header[0]->value().getStringView(), &code)) { return ret; } @@ -77,12 +81,14 @@ absl::optional FaultAbortConfig::HeaderAbortProvider::httpStatusCode absl::optional FaultAbortConfig::HeaderAbortProvider::grpcStatusCode( const Http::RequestHeaderMap* request_headers) const { auto header = request_headers->get(Filters::Common::Fault::HeaderNames::get().AbortGrpcRequest); - if (header == nullptr) { + if (header.empty()) { return absl::nullopt; } uint64_t code; - if (!absl::SimpleAtoi(header->value().getStringView(), &code)) { + // This is an implicitly untrusted header, so per the API documentation only the first + // value is used. + if (!absl::SimpleAtoi(header[0]->value().getStringView(), &code)) { return absl::nullopt; } @@ -111,12 +117,14 @@ FaultDelayConfig::FaultDelayConfig( absl::optional FaultDelayConfig::HeaderDelayProvider::duration( const Http::RequestHeaderMap* request_headers) const { const auto header = request_headers->get(HeaderNames::get().DelayRequest); - if (header == nullptr) { + if (header.empty()) { return absl::nullopt; } uint64_t value; - if (!absl::SimpleAtoi(header->value().getStringView(), &value)) { + // This is an implicitly untrusted header, so per the API documentation only the first + // value is used. + if (!absl::SimpleAtoi(header[0]->value().getStringView(), &value)) { return absl::nullopt; } @@ -142,12 +150,14 @@ FaultRateLimitConfig::FaultRateLimitConfig( absl::optional FaultRateLimitConfig::HeaderRateLimitProvider::rateKbps( const Http::RequestHeaderMap* request_headers) const { const auto header = request_headers->get(HeaderNames::get().ThroughputResponse); - if (header == nullptr) { + if (header.empty()) { return absl::nullopt; } uint64_t value; - if (!absl::SimpleAtoi(header->value().getStringView(), &value)) { + // This is an implicitly untrusted header, so per the API documentation only the first + // value is used. + if (!absl::SimpleAtoi(header[0]->value().getStringView(), &value)) { return absl::nullopt; } diff --git a/source/extensions/filters/http/aws_lambda/aws_lambda_filter.cc b/source/extensions/filters/http/aws_lambda/aws_lambda_filter.cc index e6b93b3f90e2..8822bbf3a53f 100644 --- a/source/extensions/filters/http/aws_lambda/aws_lambda_filter.cc +++ b/source/extensions/filters/http/aws_lambda/aws_lambda_filter.cc @@ -198,7 +198,7 @@ Http::FilterHeadersStatus Filter::encodeHeaders(Http::ResponseHeaderMap& headers } // Just the existence of this header means we have an error, so skip. - if (headers.get(LambdaFilterNames::get().FunctionErrorHeader)) { + if (!headers.get(LambdaFilterNames::get().FunctionErrorHeader).empty()) { skip_ = true; return Http::FilterHeadersStatus::Continue; } diff --git a/source/extensions/filters/http/cache/cache_filter.cc b/source/extensions/filters/http/cache/cache_filter.cc index f1b94a7deaa8..867c102a75f5 100644 --- a/source/extensions/filters/http/cache/cache_filter.cc +++ b/source/extensions/filters/http/cache/cache_filter.cc @@ -373,7 +373,7 @@ void CacheFilter::processSuccessfulValidation(Http::ResponseHeaderMap& response_ // TODO(yosrym93): Try to avoid copying the header key twice. Http::LowerCaseString key(std::string(cached_header.key().getStringView())); absl::string_view value = cached_header.value().getStringView(); - if (!response_headers.get(key)) { + if (response_headers.get(key).empty()) { response_headers.setCopy(key, value); } return Http::HeaderMap::Iterate::Continue; diff --git a/source/extensions/filters/http/cache/cache_headers_utils.cc b/source/extensions/filters/http/cache/cache_headers_utils.cc index b00a46bd37fe..7a412e9a131e 100644 --- a/source/extensions/filters/http/cache/cache_headers_utils.cc +++ b/source/extensions/filters/http/cache/cache_headers_utils.cc @@ -215,12 +215,13 @@ void CacheHeadersUtils::getAllMatchingHeaderNames( } std::vector -CacheHeadersUtils::parseCommaDelimitedList(const Http::HeaderEntry* entry) { - if (!entry) { +CacheHeadersUtils::parseCommaDelimitedList(const Http::HeaderMap::GetResult& entry) { + if (entry.empty()) { return {}; } - std::vector header_values = absl::StrSplit(entry->value().getStringView(), ','); + // TODO(mattklein123): Consider multiple header values? + std::vector header_values = absl::StrSplit(entry[0]->value().getStringView(), ','); for (std::string& value : header_values) { // TODO(cbdm): Might be able to improve the performance here by using StringUtil::trim to // remove whitespace. @@ -271,8 +272,9 @@ bool VaryHeader::isAllowed(const Http::ResponseHeaderMap& headers) const { } bool VaryHeader::hasVary(const Http::ResponseHeaderMap& headers) { - const Http::HeaderEntry* vary_header = headers.get(Http::Headers::get().Vary); - return vary_header != nullptr && !vary_header->value().empty(); + // TODO(mattklein123): Support multiple vary headers and/or just make the vary header inline. + const auto vary_header = headers.get(Http::Headers::get().Vary); + return !vary_header.empty() && !vary_header[0]->value().empty(); } namespace { @@ -286,13 +288,14 @@ constexpr absl::string_view header_separator = "\n"; constexpr absl::string_view in_value_separator = "\r"; }; // namespace -std::string VaryHeader::createVaryKey(const Http::HeaderEntry* vary_header, +std::string VaryHeader::createVaryKey(const Http::HeaderMap::GetResult& vary_header, const Http::RequestHeaderMap& entry_headers) { - if (vary_header == nullptr) { + if (vary_header.empty()) { return ""; } - ASSERT(vary_header->key() == "vary"); + // TODO(mattklein123): Support multiple vary headers and/or just make the vary header inline. + ASSERT(vary_header[0]->key() == "vary"); std::string vary_key = "vary-key\n"; @@ -304,10 +307,11 @@ std::string VaryHeader::createVaryKey(const Http::HeaderEntry* vary_header, // bucket UserAgent values into android/ios/desktop; UserAgent::initializeFromHeaders tries to // do that normalization and could be used as an inspiration for some bucketing configuration. // The config should enable and control the bucketing wanted. - std::vector header_values; - Http::HeaderUtility::getAllOfHeader(entry_headers, header, header_values); + const auto all_values = Http::HeaderUtility::getAllOfHeaderAsString( + entry_headers, Http::LowerCaseString(header), in_value_separator); absl::StrAppend(&vary_key, header, in_value_separator, - absl::StrJoin(header_values, in_value_separator), header_separator); + all_values.result().has_value() ? all_values.result().value() : "", + header_separator); } return vary_key; @@ -322,10 +326,10 @@ VaryHeader::possibleVariedHeaders(const Http::RequestHeaderMap& request_headers) CacheHeadersUtils::getAllMatchingHeaderNames(request_headers, allow_list_, header_names); for (const absl::string_view& header : header_names) { - std::vector values; - Http::HeaderUtility::getAllOfHeader(request_headers, header, values); - for (const absl::string_view& value : values) { - possible_headers->addCopy(Http::LowerCaseString(std::string{header}), value); + const auto lower_case_header = Http::LowerCaseString(std::string{header}); + const auto value = request_headers.get(lower_case_header); + for (size_t i = 0; i < value.size(); i++) { + possible_headers->addCopy(lower_case_header, value[i]->value().getStringView()); } } diff --git a/source/extensions/filters/http/cache/cache_headers_utils.h b/source/extensions/filters/http/cache/cache_headers_utils.h index 2ff1aa0e2a7b..aec5c78e4bcf 100644 --- a/source/extensions/filters/http/cache/cache_headers_utils.h +++ b/source/extensions/filters/http/cache/cache_headers_utils.h @@ -117,7 +117,7 @@ class CacheHeadersUtils { // Parses the values of a comma-delimited list as defined per // https://tools.ietf.org/html/rfc7230#section-7. - static std::vector parseCommaDelimitedList(const Http::HeaderEntry* entry); + static std::vector parseCommaDelimitedList(const Http::HeaderMap::GetResult& entry); }; class VaryHeader { @@ -126,7 +126,7 @@ class VaryHeader { static bool hasVary(const Http::ResponseHeaderMap& headers); // Creates a single string combining the values of the varied headers from entry_headers. - static std::string createVaryKey(const Http::HeaderEntry* vary_header, + static std::string createVaryKey(const Http::HeaderMap::GetResult& vary_header, const Http::RequestHeaderMap& entry_headers); // Parses the allow list from the Cache Config into the object's private allow_list_. diff --git a/source/extensions/filters/http/cache/cacheability_utils.cc b/source/extensions/filters/http/cache/cacheability_utils.cc index 8ddc1e63c6d4..48f0d48369cd 100644 --- a/source/extensions/filters/http/cache/cacheability_utils.cc +++ b/source/extensions/filters/http/cache/cacheability_utils.cc @@ -43,7 +43,7 @@ bool CacheabilityUtils::isCacheableRequest(const Http::RequestHeaderMap& headers // If needed to be handled properly refer to: // https://httpwg.org/specs/rfc7234.html#validation.received for (auto conditional_header : conditionalHeaders()) { - if (headers.get(*conditional_header)) { + if (!headers.get(*conditional_header).empty()) { return false; } } diff --git a/source/extensions/filters/http/cache/http_cache.cc b/source/extensions/filters/http/cache/http_cache.cc index 4acb65938f1e..453da7ecd3bd 100644 --- a/source/extensions/filters/http/cache/http_cache.cc +++ b/source/extensions/filters/http/cache/http_cache.cc @@ -214,15 +214,13 @@ std::vector RangeRequests::parseRanges(const Http::RequestHeaderMa // Multiple instances of range headers are invalid. // https://tools.ietf.org/html/rfc7230#section-3.2.2 - std::vector range_headers; - Http::HeaderUtility::getAllOfHeader(request_headers, Http::Headers::get().Range.get(), - range_headers); + const auto range_header = request_headers.get(Http::Headers::get().Range); absl::string_view header_value; - if (range_headers.size() == 1) { - header_value = range_headers.front(); + if (range_header.size() == 1) { + header_value = range_header[0]->value().getStringView(); } else { - if (range_headers.size() > 1) { + if (range_header.size() > 1) { ENVOY_LOG(debug, "Multiple range headers provided in request. Ignoring all range headers."); } return {}; diff --git a/source/extensions/filters/http/cache/simple_http_cache/simple_http_cache.cc b/source/extensions/filters/http/cache/simple_http_cache/simple_http_cache.cc index 0fea6205801c..dcea0e448d4b 100644 --- a/source/extensions/filters/http/cache/simple_http_cache/simple_http_cache.cc +++ b/source/extensions/filters/http/cache/simple_http_cache/simple_http_cache.cc @@ -144,8 +144,8 @@ SimpleHttpCache::varyLookup(const LookupRequest& request, // This method should be called from lookup, which holds the mutex for reading. mutex_.AssertReaderHeld(); - const Http::HeaderEntry* vary_header = response_headers->get(Http::Headers::get().Vary); - ASSERT(vary_header); + const auto vary_header = response_headers->get(Http::Headers::get().Vary); + ASSERT(!vary_header.empty()); Key varied_request_key = request.key(); const std::string vary_key = VaryHeader::createVaryKey(vary_header, request.getVaryHeaders()); @@ -168,8 +168,8 @@ void SimpleHttpCache::varyInsert(const Key& request_key, const Http::RequestHeaderMap& request_vary_headers) { absl::WriterMutexLock lock(&mutex_); - const Http::HeaderEntry* vary_header = response_headers->get(Http::Headers::get().Vary); - ASSERT(vary_header); + const auto vary_header = response_headers->get(Http::Headers::get().Vary); + ASSERT(!vary_header.empty()); // Insert the varied response. Key varied_request_key = request_key; @@ -183,7 +183,8 @@ void SimpleHttpCache::varyInsert(const Key& request_key, if (iter == map_.end()) { Http::ResponseHeaderMapPtr vary_only_map = Http::createHeaderMap({}); - vary_only_map->setCopy(Http::Headers::get().Vary, vary_header->value().getStringView()); + // TODO(mattklein123): Support multiple vary headers and/or just make the vary header inline. + vary_only_map->setCopy(Http::Headers::get().Vary, vary_header[0]->value().getStringView()); // TODO(cbdm): In a cache that evicts entries, we could maintain a list of the "varykey"s that // we have inserted as the body for this first lookup. This way, we would know which keys we // have inserted for that resource. For the first entry simply use vary_key as the entry_list, diff --git a/source/extensions/filters/http/dynamic_forward_proxy/proxy_filter.cc b/source/extensions/filters/http/dynamic_forward_proxy/proxy_filter.cc index b41b0cf07d91..f684bad7571d 100644 --- a/source/extensions/filters/http/dynamic_forward_proxy/proxy_filter.cc +++ b/source/extensions/filters/http/dynamic_forward_proxy/proxy_filter.cc @@ -108,9 +108,11 @@ Http::FilterHeadersStatus ProxyFilter::decodeHeaders(Http::RequestHeaderMap& hea const auto& host_rewrite_header = config->hostRewriteHeader(); if (!host_rewrite_header.get().empty()) { - const auto* header = headers.get(host_rewrite_header); - if (header != nullptr) { - const auto& header_value = header->value().getStringView(); + const auto header = headers.get(host_rewrite_header); + if (!header.empty()) { + // This is an implicitly untrusted header, so per the API documentation only the first + // value is used. + const auto& header_value = header[0]->value().getStringView(); headers.setHost(header_value); } } diff --git a/source/extensions/filters/http/dynamo/dynamo_request_parser.cc b/source/extensions/filters/http/dynamo/dynamo_request_parser.cc index dd34cbc81b0a..6fd0a1d42a84 100644 --- a/source/extensions/filters/http/dynamo/dynamo_request_parser.cc +++ b/source/extensions/filters/http/dynamo/dynamo_request_parser.cc @@ -65,10 +65,12 @@ const std::vector RequestParser::TRANSACT_ITEM_OPERATIONS{"Conditio std::string RequestParser::parseOperation(const Http::HeaderMap& header_map) { std::string operation; - const Http::HeaderEntry* x_amz_target = header_map.get(X_AMZ_TARGET); - if (x_amz_target) { + const auto x_amz_target = header_map.get(X_AMZ_TARGET); + if (!x_amz_target.empty()) { // Normally x-amz-target contains Version.Operation, e.g., DynamoDB_20160101.GetItem - auto version_and_operation = StringUtil::splitToken(x_amz_target->value().getStringView(), "."); + // AWS is trusted. Using the first value is fine. + auto version_and_operation = + StringUtil::splitToken(x_amz_target[0]->value().getStringView(), "."); if (version_and_operation.size() == 2) { operation = std::string{version_and_operation[1]}; } diff --git a/source/extensions/filters/http/ext_authz/ext_authz.cc b/source/extensions/filters/http/ext_authz/ext_authz.cc index cb3bd5c491ad..38d86bc85709 100644 --- a/source/extensions/filters/http/ext_authz/ext_authz.cc +++ b/source/extensions/filters/http/ext_authz/ext_authz.cc @@ -191,7 +191,7 @@ void Filter::onComplete(Filters::Common::ExtAuthz::ResponsePtr&& response) { request_headers_->addCopy(header.first, header.second); } for (const auto& header : response->headers_to_append) { - const Http::HeaderEntry* header_to_modify = request_headers_->get(header.first); + const auto header_to_modify = request_headers_->get(header.first); // TODO(dio): Add a flag to allow appending non-existent headers, without setting it first // (via `headers_to_add`). For example, given: // 1. Original headers {"original": "true"} @@ -200,7 +200,7 @@ void Filter::onComplete(Filters::Common::ExtAuthz::ResponsePtr&& response) { // Currently it is not possible to add {{"append": "1"}, {"append": "2"}} (the intended // combined headers: {{"original": "true"}, {"append": "1"}, {"append": "2"}}) to the request // to upstream server by only sets `headers_to_append`. - if (header_to_modify != nullptr) { + if (!header_to_modify.empty()) { ENVOY_STREAM_LOG(trace, "'{}':'{}'", *callbacks_, header.first.get(), header.second); // The current behavior of appending is by combining entries with the same key, into one // entry. The value of that combined entry is separated by ",". diff --git a/source/extensions/filters/http/squash/squash_filter.cc b/source/extensions/filters/http/squash/squash_filter.cc index ae1d4206f2bd..b58052124143 100644 --- a/source/extensions/filters/http/squash/squash_filter.cc +++ b/source/extensions/filters/http/squash/squash_filter.cc @@ -138,7 +138,7 @@ void SquashFilter::onDestroy() { cleanup(); } Http::FilterHeadersStatus SquashFilter::decodeHeaders(Http::RequestHeaderMap& headers, bool) { // Check for squash header - if (!headers.get(Http::Headers::get().XSquashDebug)) { + if (headers.get(Http::Headers::get().XSquashDebug).empty()) { return Http::FilterHeadersStatus::Continue; } diff --git a/source/extensions/filters/network/thrift_proxy/router/router_impl.cc b/source/extensions/filters/network/thrift_proxy/router/router_impl.cc index f3910f0614bc..aa10f24d5b71 100644 --- a/source/extensions/filters/network/thrift_proxy/router/router_impl.cc +++ b/source/extensions/filters/network/thrift_proxy/router/router_impl.cc @@ -63,9 +63,11 @@ RouteConstSharedPtr RouteEntryImplBase::clusterEntry(uint64_t random_value, const auto& cluster_header = clusterHeader(); if (!cluster_header.get().empty()) { const auto& headers = metadata.headers(); - const auto* entry = headers.get(cluster_header); - if (entry != nullptr) { - return std::make_shared(*this, entry->value().getStringView()); + const auto entry = headers.get(cluster_header); + if (!entry.empty()) { + // This is an implicitly untrusted header, so per the API documentation only the first + // value is used. + return std::make_shared(*this, entry[0]->value().getStringView()); } return nullptr; diff --git a/source/extensions/filters/network/thrift_proxy/router/router_ratelimit_impl.cc b/source/extensions/filters/network/thrift_proxy/router/router_ratelimit_impl.cc index 694831013a42..01d4154a4d08 100644 --- a/source/extensions/filters/network/thrift_proxy/router/router_ratelimit_impl.cc +++ b/source/extensions/filters/network/thrift_proxy/router/router_ratelimit_impl.cc @@ -40,13 +40,14 @@ bool RequestHeadersAction::populateDescriptor(const RouteEntry&, RateLimit::Desc return true; } - const Http::HeaderEntry* header_value = metadata.headers().get(header_name_); - if (!header_value) { + const auto header_value = metadata.headers().get(header_name_); + if (header_value.empty()) { return false; } + // TODO(https://github.com/envoyproxy/envoy/issues/13454): Potentially populate all values. descriptor.entries_.push_back( - {descriptor_key_, std::string(header_value->value().getStringView())}); + {descriptor_key_, std::string(header_value[0]->value().getStringView())}); return true; } diff --git a/source/extensions/tracers/common/ot/opentracing_driver_impl.cc b/source/extensions/tracers/common/ot/opentracing_driver_impl.cc index cad01b83bb83..18bf1e828dcc 100644 --- a/source/extensions/tracers/common/ot/opentracing_driver_impl.cc +++ b/source/extensions/tracers/common/ot/opentracing_driver_impl.cc @@ -48,10 +48,11 @@ class OpenTracingHTTPHeadersReader : public opentracing::HTTPHeadersReader { // opentracing::HTTPHeadersReader opentracing::expected LookupKey(opentracing::string_view key) const override { - const Http::HeaderEntry* entry = request_headers_.get(Http::LowerCaseString{key}); - if (entry != nullptr) { - return opentracing::string_view{entry->value().getStringView().data(), - entry->value().getStringView().length()}; + const auto entry = request_headers_.get(Http::LowerCaseString{key}); + if (!entry.empty()) { + // This is an implicitly untrusted header, so only the first value is used. + return opentracing::string_view{entry[0]->value().getStringView().data(), + entry[0]->value().getStringView().length()}; } else { return opentracing::make_unexpected(opentracing::key_not_found_error); } diff --git a/source/extensions/tracers/opencensus/opencensus_tracer_impl.cc b/source/extensions/tracers/opencensus/opencensus_tracer_impl.cc index 41bd08e03d44..50b5fdac8039 100644 --- a/source/extensions/tracers/opencensus/opencensus_tracer_impl.cc +++ b/source/extensions/tracers/opencensus/opencensus_tracer_impl.cc @@ -92,31 +92,34 @@ startSpanHelper(const std::string& name, bool traced, const Http::RequestHeaderM bool found = false; switch (incoming) { case OpenCensusConfig::TRACE_CONTEXT: { - const Http::HeaderEntry* header = request_headers.get(Constants::get().TRACEPARENT); - if (header != nullptr) { + const auto header = request_headers.get(Constants::get().TRACEPARENT); + if (!header.empty()) { found = true; + // This is an implicitly untrusted header, so only the first value is used. parent_ctx = ::opencensus::trace::propagation::FromTraceParentHeader( - header->value().getStringView()); + header[0]->value().getStringView()); } break; } case OpenCensusConfig::GRPC_TRACE_BIN: { - const Http::HeaderEntry* header = request_headers.get(Constants::get().GRPC_TRACE_BIN); - if (header != nullptr) { + const auto header = request_headers.get(Constants::get().GRPC_TRACE_BIN); + if (!header.empty()) { found = true; + // This is an implicitly untrusted header, so only the first value is used. parent_ctx = ::opencensus::trace::propagation::FromGrpcTraceBinHeader( - Base64::decodeWithoutPadding(header->value().getStringView())); + Base64::decodeWithoutPadding(header[0]->value().getStringView())); } break; } case OpenCensusConfig::CLOUD_TRACE_CONTEXT: { - const Http::HeaderEntry* header = request_headers.get(Constants::get().X_CLOUD_TRACE_CONTEXT); - if (header != nullptr) { + const auto header = request_headers.get(Constants::get().X_CLOUD_TRACE_CONTEXT); + if (!header.empty()) { found = true; + // This is an implicitly untrusted header, so only the first value is used. parent_ctx = ::opencensus::trace::propagation::FromCloudTraceContextHeader( - header->value().getStringView()); + header[0]->value().getStringView()); } break; } @@ -126,23 +129,27 @@ startSpanHelper(const std::string& name, bool traced, const Http::RequestHeaderM absl::string_view b3_span_id; absl::string_view b3_sampled; absl::string_view b3_flags; - const Http::HeaderEntry* h_b3_trace_id = request_headers.get(Constants::get().X_B3_TRACEID); - if (h_b3_trace_id != nullptr) { - b3_trace_id = h_b3_trace_id->value().getStringView(); + const auto h_b3_trace_id = request_headers.get(Constants::get().X_B3_TRACEID); + if (!h_b3_trace_id.empty()) { + // This is an implicitly untrusted header, so only the first value is used. + b3_trace_id = h_b3_trace_id[0]->value().getStringView(); } - const Http::HeaderEntry* h_b3_span_id = request_headers.get(Constants::get().X_B3_SPANID); - if (h_b3_span_id != nullptr) { - b3_span_id = h_b3_span_id->value().getStringView(); + const auto h_b3_span_id = request_headers.get(Constants::get().X_B3_SPANID); + if (!h_b3_span_id.empty()) { + // This is an implicitly untrusted header, so only the first value is used. + b3_span_id = h_b3_span_id[0]->value().getStringView(); } - const Http::HeaderEntry* h_b3_sampled = request_headers.get(Constants::get().X_B3_SAMPLED); - if (h_b3_sampled != nullptr) { - b3_sampled = h_b3_sampled->value().getStringView(); + const auto h_b3_sampled = request_headers.get(Constants::get().X_B3_SAMPLED); + if (!h_b3_sampled.empty()) { + // This is an implicitly untrusted header, so only the first value is used. + b3_sampled = h_b3_sampled[0]->value().getStringView(); } - const Http::HeaderEntry* h_b3_flags = request_headers.get(Constants::get().X_B3_FLAGS); - if (h_b3_flags != nullptr) { - b3_flags = h_b3_flags->value().getStringView(); + const auto h_b3_flags = request_headers.get(Constants::get().X_B3_FLAGS); + if (!h_b3_flags.empty()) { + // This is an implicitly untrusted header, so only the first value is used. + b3_flags = h_b3_flags[0]->value().getStringView(); } - if (h_b3_trace_id != nullptr && h_b3_span_id != nullptr) { + if (!h_b3_trace_id.empty() && !h_b3_span_id.empty()) { found = true; parent_ctx = ::opencensus::trace::propagation::FromB3Headers(b3_trace_id, b3_span_id, b3_sampled, b3_flags); diff --git a/source/extensions/tracers/xray/xray_tracer_impl.cc b/source/extensions/tracers/xray/xray_tracer_impl.cc index d2fa82cf88b5..77e240c783a2 100644 --- a/source/extensions/tracers/xray/xray_tracer_impl.cc +++ b/source/extensions/tracers/xray/xray_tracer_impl.cc @@ -77,11 +77,12 @@ Tracing::SpanPtr Driver::startSpan(const Tracing::Config& config, UNREFERENCED_PARAMETER(config); // TODO(marcomagdy) - how do we factor this into the logic above UNREFERENCED_PARAMETER(tracing_decision); - const auto* header = request_headers.get(Http::LowerCaseString(XRayTraceHeader)); + const auto header = request_headers.get(Http::LowerCaseString(XRayTraceHeader)); absl::optional should_trace; XRayHeader xray_header; - if (header) { - Http::LowerCaseString lowered_header_value{std::string(header->value().getStringView())}; + if (!header.empty()) { + // This is an implicitly untrusted header, so only the first value is used. + Http::LowerCaseString lowered_header_value{std::string(header[0]->value().getStringView())}; xray_header = parseXRayHeader(lowered_header_value); // if the sample_decision in the x-ray header is unknown then we try to make a decision based // on the sampling strategy @@ -107,7 +108,8 @@ Tracing::SpanPtr Driver::startSpan(const Tracing::Config& config, auto* tracer = tls_slot_ptr_->getTyped().tracer_.get(); if (should_trace.value()) { return tracer->startSpan(operation_name, start_time, - header ? absl::optional(xray_header) : absl::nullopt); + !header.empty() ? absl::optional(xray_header) + : absl::nullopt); } // instead of returning nullptr, we return a Span that is marked as not-sampled. diff --git a/source/extensions/tracers/zipkin/span_context_extractor.cc b/source/extensions/tracers/zipkin/span_context_extractor.cc index 0f48986f4437..a9b67503ffd1 100644 --- a/source/extensions/tracers/zipkin/span_context_extractor.cc +++ b/source/extensions/tracers/zipkin/span_context_extractor.cc @@ -37,8 +37,9 @@ SpanContextExtractor::~SpanContextExtractor() = default; bool SpanContextExtractor::extractSampled(const Tracing::Decision tracing_decision) { bool sampled(false); auto b3_header_entry = request_headers_.get(ZipkinCoreConstants::get().B3); - if (b3_header_entry) { - absl::string_view b3 = b3_header_entry->value().getStringView(); + if (!b3_header_entry.empty()) { + // This is an implicitly untrusted header, so only the first value is used. + absl::string_view b3 = b3_header_entry[0]->value().getStringView(); int sampled_pos = 0; switch (b3.length()) { case 1: @@ -62,18 +63,19 @@ bool SpanContextExtractor::extractSampled(const Tracing::Decision tracing_decisi } auto x_b3_sampled_entry = request_headers_.get(ZipkinCoreConstants::get().X_B3_SAMPLED); - if (!x_b3_sampled_entry) { + if (x_b3_sampled_entry.empty()) { return tracing_decision.traced; } // Checking if sampled flag has been specified. Also checking for 'true' value, as some old // zipkin tracers may still use that value, although should be 0 or 1. - absl::string_view xb3_sampled = x_b3_sampled_entry->value().getStringView(); + // This is an implicitly untrusted header, so only the first value is used. + absl::string_view xb3_sampled = x_b3_sampled_entry[0]->value().getStringView(); sampled = xb3_sampled == SAMPLED || xb3_sampled == "true"; return sampled; } std::pair SpanContextExtractor::extractSpanContext(bool is_sampled) { - if (request_headers_.get(ZipkinCoreConstants::get().B3)) { + if (!request_headers_.get(ZipkinCoreConstants::get().B3).empty()) { return extractSpanContextFromB3SingleFormat(is_sampled); } uint64_t trace_id(0); @@ -83,11 +85,12 @@ std::pair SpanContextExtractor::extractSpanContext(bool is_sa auto b3_trace_id_entry = request_headers_.get(ZipkinCoreConstants::get().X_B3_TRACE_ID); auto b3_span_id_entry = request_headers_.get(ZipkinCoreConstants::get().X_B3_SPAN_ID); - if (b3_span_id_entry && b3_trace_id_entry) { + if (!b3_span_id_entry.empty() && !b3_trace_id_entry.empty()) { // Extract trace id - which can either be 128 or 64 bit. For 128 bit, // it needs to be divided into two 64 bit numbers (high and low). - const std::string tid(b3_trace_id_entry->value().getStringView()); - if (b3_trace_id_entry->value().size() == 32) { + // This is an implicitly untrusted header, so only the first value is used. + const std::string tid(b3_trace_id_entry[0]->value().getStringView()); + if (b3_trace_id_entry[0]->value().size() == 32) { const std::string high_tid = tid.substr(0, 16); const std::string low_tid = tid.substr(16, 16); if (!StringUtil::atoull(high_tid.c_str(), trace_id_high, 16) || @@ -99,14 +102,16 @@ std::pair SpanContextExtractor::extractSpanContext(bool is_sa throw ExtractorException(absl::StrCat("Invalid trace_id ", tid.c_str())); } - const std::string spid(b3_span_id_entry->value().getStringView()); + // This is an implicitly untrusted header, so only the first value is used. + const std::string spid(b3_span_id_entry[0]->value().getStringView()); if (!StringUtil::atoull(spid.c_str(), span_id, 16)) { throw ExtractorException(absl::StrCat("Invalid span id ", spid.c_str())); } auto b3_parent_id_entry = request_headers_.get(ZipkinCoreConstants::get().X_B3_PARENT_SPAN_ID); - if (b3_parent_id_entry && !b3_parent_id_entry->value().empty()) { - const std::string pspid(b3_parent_id_entry->value().getStringView()); + if (!b3_parent_id_entry.empty() && !b3_parent_id_entry[0]->value().empty()) { + // This is an implicitly untrusted header, so only the first value is used. + const std::string pspid(b3_parent_id_entry[0]->value().getStringView()); if (!StringUtil::atoull(pspid.c_str(), parent_id, 16)) { throw ExtractorException(absl::StrCat("Invalid parent span id ", pspid.c_str())); } @@ -121,8 +126,9 @@ std::pair SpanContextExtractor::extractSpanContext(bool is_sa std::pair SpanContextExtractor::extractSpanContextFromB3SingleFormat(bool is_sampled) { auto b3_head_entry = request_headers_.get(ZipkinCoreConstants::get().B3); - ASSERT(b3_head_entry); - const std::string b3(b3_head_entry->value().getStringView()); + ASSERT(!b3_head_entry.empty()); + // This is an implicitly untrusted header, so only the first value is used. + const std::string b3(b3_head_entry[0]->value().getStringView()); if (!b3.length()) { throw ExtractorException("Invalid input: empty"); } diff --git a/source/server/admin/utils.cc b/source/server/admin/utils.cc index eaa5a6689a02..4bc16f2cc515 100644 --- a/source/server/admin/utils.cc +++ b/source/server/admin/utils.cc @@ -28,7 +28,7 @@ void populateFallbackResponseHeaders(Http::Code code, Http::ResponseHeaderMap& h header_map.setReferenceContentType(Http::Headers::get().ContentTypeValues.TextUtf8); } // Default to 'no-cache' if unset, but not 'no-store' which may break the back button. - if (header_map.get(Http::CustomHeaders::get().CacheControl) == nullptr) { + if (header_map.get(Http::CustomHeaders::get().CacheControl).empty()) { header_map.setReference(Http::CustomHeaders::get().CacheControl, Http::CustomHeaders::get().CacheControlValues.NoCacheMaxAge0); } diff --git a/test/common/grpc/async_client_impl_test.cc b/test/common/grpc/async_client_impl_test.cc index 8340b56aeda9..4e690c9d5a19 100644 --- a/test/common/grpc/async_client_impl_test.cc +++ b/test/common/grpc/async_client_impl_test.cc @@ -121,7 +121,7 @@ TEST_F(EnvoyAsyncClientImplTest, MetadataIsInitialized) { EXPECT_CALL(grpc_callbacks, onCreateInitialMetadata(testing::Truly([&expected_downstream_local_address]( Http::RequestHeaderMap& headers) { - return headers.get(Http::LowerCaseString("downstream-local-address"))->value() == + return headers.get(Http::LowerCaseString("downstream-local-address"))[0]->value() == expected_downstream_local_address; }))); EXPECT_CALL(http_stream, sendHeaders(_, _)) diff --git a/test/common/grpc/google_async_client_impl_test.cc b/test/common/grpc/google_async_client_impl_test.cc index 7ecbf57bc5cf..31e732d98d85 100644 --- a/test/common/grpc/google_async_client_impl_test.cc +++ b/test/common/grpc/google_async_client_impl_test.cc @@ -113,7 +113,7 @@ TEST_F(EnvoyGoogleAsyncClientImplTest, MetadataIsInitialized) { EXPECT_CALL(grpc_callbacks, onCreateInitialMetadata(testing::Truly([&expected_downstream_local_address]( Http::RequestHeaderMap& headers) { - return headers.get(Http::LowerCaseString("downstream-local-address"))->value() == + return headers.get(Http::LowerCaseString("downstream-local-address"))[0]->value() == expected_downstream_local_address; }))); diff --git a/test/common/grpc/grpc_client_integration_test.cc b/test/common/grpc/grpc_client_integration_test.cc index e347226f0354..f1c8d83d8d83 100644 --- a/test/common/grpc/grpc_client_integration_test.cc +++ b/test/common/grpc/grpc_client_integration_test.cc @@ -413,13 +413,12 @@ class GrpcAccessTokenClientIntegrationTest : public GrpcSslClientIntegrationTest void expectExtraHeaders(FakeStream& fake_stream) override { AssertionResult result = fake_stream.waitForHeadersComplete(); RELEASE_ASSERT(result, result.message()); - std::vector auth_headers; - Http::HeaderUtility::getAllOfHeader(fake_stream.headers(), "authorization", auth_headers); + const auto auth_headers = fake_stream.headers().get(Http::LowerCaseString("authorization")); if (!access_token_value_.empty()) { - EXPECT_EQ("Bearer " + access_token_value_, auth_headers[0]); + EXPECT_EQ("Bearer " + access_token_value_, auth_headers[0]->value().getStringView()); } if (!access_token_value_2_.empty()) { - EXPECT_EQ("Bearer " + access_token_value_2_, auth_headers[1]); + EXPECT_EQ("Bearer " + access_token_value_2_, auth_headers[1]->value().getStringView()); } } diff --git a/test/common/http/conn_manager_impl_test_2.cc b/test/common/http/conn_manager_impl_test_2.cc index 78dc20b6251c..6a7ed3ab088a 100644 --- a/test/common/http/conn_manager_impl_test_2.cc +++ b/test/common/http/conn_manager_impl_test_2.cc @@ -499,7 +499,7 @@ TEST_F(HttpConnectionManagerImplTest, FilterAddTrailersInTrailersCallback) { EXPECT_CALL(*decoder_filters_[1], decodeTrailers(_)) .WillOnce(Invoke([&](Http::HeaderMap& trailers) -> FilterTrailersStatus { Http::LowerCaseString key("foo"); - EXPECT_EQ(trailers.get(key), nullptr); + EXPECT_TRUE(trailers.get(key).empty()); return FilterTrailersStatus::Continue; })); EXPECT_CALL(*decoder_filters_[1], decodeComplete()); @@ -539,7 +539,7 @@ TEST_F(HttpConnectionManagerImplTest, FilterAddTrailersInTrailersCallback) { .WillOnce(Invoke([&](Http::HeaderMap& trailers) -> FilterTrailersStatus { // assert that the trailers set in the previous filter was ignored Http::LowerCaseString key("foo"); - EXPECT_EQ(trailers.get(key), nullptr); + EXPECT_TRUE(trailers.get(key).empty()); return FilterTrailersStatus::Continue; })); EXPECT_CALL(*encoder_filters_[0], encodeComplete()); @@ -577,8 +577,8 @@ TEST_F(HttpConnectionManagerImplTest, FilterAddTrailersInDataCallbackNoTrailers) // ensure that we see the trailers set in decodeData Http::LowerCaseString key("foo"); auto t = trailers.get(key); - ASSERT(t); - EXPECT_EQ(t->value(), trailers_data.c_str()); + ASSERT(!t.empty()); + EXPECT_EQ(t[0]->value(), trailers_data.c_str()); return FilterTrailersStatus::Continue; })); EXPECT_CALL(*decoder_filters_[1], decodeComplete()); @@ -616,7 +616,7 @@ TEST_F(HttpConnectionManagerImplTest, FilterAddTrailersInDataCallbackNoTrailers) // ensure that we see the trailers set in decodeData Http::LowerCaseString key("foo"); auto t = trailers.get(key); - EXPECT_EQ(t->value(), trailers_data.c_str()); + EXPECT_EQ(t[0]->value(), trailers_data.c_str()); return FilterTrailersStatus::Continue; })); EXPECT_CALL(*encoder_filters_[0], encodeComplete()); diff --git a/test/common/http/header_map_impl_fuzz_test.cc b/test/common/http/header_map_impl_fuzz_test.cc index 5600af1c3160..abbe77e6ca1c 100644 --- a/test/common/http/header_map_impl_fuzz_test.cc +++ b/test/common/http/header_map_impl_fuzz_test.cc @@ -94,14 +94,14 @@ DEFINE_PROTO_FUZZER(const test::common::http::HeaderMapImplFuzzTestCase& input) } case test::common::http::Action::kGet: { const auto& get = action.get(); - const auto* header_entry = + const auto header_entry = header_map->get(Http::LowerCaseString(replaceInvalidCharacters(get.key()))); - if (header_entry != nullptr) { + for (size_t i = 0; i < header_entry.size(); i++) { // Do some read-only stuff. - (void)strlen(std::string(header_entry->key().getStringView()).c_str()); - (void)strlen(std::string(header_entry->value().getStringView()).c_str()); - header_entry->key().empty(); - header_entry->value().empty(); + (void)strlen(std::string(header_entry[i]->key().getStringView()).c_str()); + (void)strlen(std::string(header_entry[i]->value().getStringView()).c_str()); + header_entry[i]->key().empty(); + header_entry[i]->value().empty(); } break; } diff --git a/test/common/http/header_map_impl_speed_test.cc b/test/common/http/header_map_impl_speed_test.cc index 66e1f9b8dc06..62a0c12972ff 100644 --- a/test/common/http/header_map_impl_speed_test.cc +++ b/test/common/http/header_map_impl_speed_test.cc @@ -63,7 +63,7 @@ static void headerMapImplGet(benchmark::State& state) { headers->setReference(key, value); size_t successes = 0; for (auto _ : state) { // NOLINT - successes += (headers->get(key) != nullptr); + successes += !headers->get(key).empty(); } benchmark::DoNotOptimize(successes); } diff --git a/test/common/http/header_map_impl_test.cc b/test/common/http/header_map_impl_test.cc index ba55a42220ec..88888a7d67e0 100644 --- a/test/common/http/header_map_impl_test.cc +++ b/test/common/http/header_map_impl_test.cc @@ -397,7 +397,7 @@ TEST_P(HeaderMapImplTest, CustomRegisteredHeaders) { header_map->remove##name(); \ EXPECT_EQ(nullptr, header_map->name()); \ header_map->set##name(#name); \ - EXPECT_EQ(header_map->get(Headers::get().name)->value().getStringView(), #name); + EXPECT_EQ(header_map->get(Headers::get().name)[0]->value().getStringView(), #name); // Make sure that the O(1) headers are wired up properly. TEST_P(HeaderMapImplTest, AllInlineHeaders) { @@ -430,7 +430,7 @@ TEST_P(HeaderMapImplTest, InlineInsert) { EXPECT_EQ(1, headers.size()); EXPECT_EQ(":authority", headers.Host()->key().getStringView()); EXPECT_EQ("hello", headers.getHostValue()); - EXPECT_EQ("hello", headers.get(Headers::get().Host)->value().getStringView()); + EXPECT_EQ("hello", headers.get(Headers::get().Host)[0]->value().getStringView()); } TEST_P(HeaderMapImplTest, InlineAppend) { @@ -505,12 +505,12 @@ TEST_P(HeaderMapImplTest, Remove) { LowerCaseString static_key("hello"); std::string ref_value("value"); headers.addReference(static_key, ref_value); - EXPECT_EQ("value", headers.get(static_key)->value().getStringView()); - EXPECT_TRUE(headers.get(static_key)->value().isReference()); + EXPECT_EQ("value", headers.get(static_key)[0]->value().getStringView()); + EXPECT_TRUE(headers.get(static_key)[0]->value().isReference()); EXPECT_EQ(1UL, headers.size()); EXPECT_FALSE(headers.empty()); EXPECT_EQ(1UL, headers.remove(static_key)); - EXPECT_EQ(nullptr, headers.get(static_key)); + EXPECT_TRUE(headers.get(static_key).empty()); EXPECT_EQ(0UL, headers.size()); EXPECT_TRUE(headers.empty()); @@ -615,19 +615,19 @@ TEST_P(HeaderMapImplTest, RemovePrefix) { // Test removing the first header, middle headers, and the end header. EXPECT_EQ(3UL, headers.removePrefix(LowerCaseString("x-prefix-"))); - EXPECT_EQ(nullptr, headers.get(key1)); - EXPECT_NE(nullptr, headers.get(key2)); - EXPECT_EQ(nullptr, headers.get(key3)); - EXPECT_NE(nullptr, headers.get(key4)); - EXPECT_EQ(nullptr, headers.get(key5)); + EXPECT_TRUE(headers.get(key1).empty()); + EXPECT_FALSE(headers.get(key2).empty()); + EXPECT_TRUE(headers.get(key3).empty()); + EXPECT_FALSE(headers.get(key4).empty()); + EXPECT_TRUE(headers.get(key5).empty()); // Try to remove headers with no prefix match. EXPECT_EQ(0UL, headers.removePrefix(LowerCaseString("foo"))); // Remove all headers. EXPECT_EQ(2UL, headers.removePrefix(LowerCaseString(""))); - EXPECT_EQ(nullptr, headers.get(key2)); - EXPECT_EQ(nullptr, headers.get(key4)); + EXPECT_TRUE(headers.get(key2).empty()); + EXPECT_TRUE(headers.get(key4).empty()); // Add inline and remove by prefix headers.setContentLength(5); @@ -735,11 +735,10 @@ TEST_P(HeaderMapImplTest, DoubleCookieAdd) { headers.addReference(set_cookie, bar); EXPECT_EQ(2UL, headers.size()); - std::vector out; - Http::HeaderUtility::getAllOfHeader(headers, "set-cookie", out); - ASSERT_EQ(out.size(), 2); - ASSERT_EQ(out[0], "foo"); - ASSERT_EQ(out[1], "bar"); + const auto set_cookie_value = headers.get(LowerCaseString("set-cookie")); + ASSERT_EQ(set_cookie_value.size(), 2); + ASSERT_EQ(set_cookie_value[0]->value().getStringView(), "foo"); + ASSERT_EQ(set_cookie_value[1]->value().getStringView(), "bar"); } TEST_P(HeaderMapImplTest, DoubleInlineSet) { @@ -754,20 +753,20 @@ TEST_P(HeaderMapImplTest, AddReferenceKey) { TestRequestHeaderMapImpl headers; LowerCaseString foo("hello"); headers.addReferenceKey(foo, "world"); - EXPECT_NE("world", headers.get(foo)->value().getStringView().data()); - EXPECT_EQ("world", headers.get(foo)->value().getStringView()); + EXPECT_NE("world", headers.get(foo)[0]->value().getStringView().data()); + EXPECT_EQ("world", headers.get(foo)[0]->value().getStringView()); } TEST_P(HeaderMapImplTest, SetReferenceKey) { TestRequestHeaderMapImpl headers; LowerCaseString foo("hello"); headers.setReferenceKey(foo, "world"); - EXPECT_NE("world", headers.get(foo)->value().getStringView().data()); - EXPECT_EQ("world", headers.get(foo)->value().getStringView()); + EXPECT_NE("world", headers.get(foo)[0]->value().getStringView().data()); + EXPECT_EQ("world", headers.get(foo)[0]->value().getStringView()); headers.setReferenceKey(foo, "monde"); - EXPECT_NE("monde", headers.get(foo)->value().getStringView().data()); - EXPECT_EQ("monde", headers.get(foo)->value().getStringView()); + EXPECT_NE("monde", headers.get(foo)[0]->value().getStringView().data()); + EXPECT_EQ("monde", headers.get(foo)[0]->value().getStringView()); } TEST_P(HeaderMapImplTest, SetCopyOldBehavior) { @@ -777,11 +776,11 @@ TEST_P(HeaderMapImplTest, SetCopyOldBehavior) { TestRequestHeaderMapImpl headers; LowerCaseString foo("hello"); headers.setCopy(foo, "world"); - EXPECT_EQ("world", headers.get(foo)->value().getStringView()); + EXPECT_EQ("world", headers.get(foo)[0]->value().getStringView()); // Overwrite value. headers.setCopy(foo, "monde"); - EXPECT_EQ("monde", headers.get(foo)->value().getStringView()); + EXPECT_EQ("monde", headers.get(foo)[0]->value().getStringView()); // Add another foo header. headers.addCopy(foo, "monde2"); @@ -805,7 +804,7 @@ TEST_P(HeaderMapImplTest, SetCopyOldBehavior) { headers.setCopy(foo, empty); EXPECT_EQ(headers.size(), 1); headers.setCopy(foo, "not-empty"); - EXPECT_EQ(headers.get(foo)->value().getStringView(), "not-empty"); + EXPECT_EQ(headers.get(foo)[0]->value().getStringView(), "not-empty"); // Use setCopy with inline headers both indirectly and directly. headers.clear(); @@ -822,11 +821,11 @@ TEST_P(HeaderMapImplTest, SetCopyNewBehavior) { TestRequestHeaderMapImpl headers; LowerCaseString foo("hello"); headers.setCopy(foo, "world"); - EXPECT_EQ("world", headers.get(foo)->value().getStringView()); + EXPECT_EQ("world", headers.get(foo)[0]->value().getStringView()); // Overwrite value. headers.setCopy(foo, "monde"); - EXPECT_EQ("monde", headers.get(foo)->value().getStringView()); + EXPECT_EQ("monde", headers.get(foo)[0]->value().getStringView()); // Add another foo header. headers.addCopy(foo, "monde2"); @@ -849,7 +848,7 @@ TEST_P(HeaderMapImplTest, SetCopyNewBehavior) { headers.setCopy(foo, empty); EXPECT_EQ(headers.size(), 1); headers.setCopy(foo, "not-empty"); - EXPECT_EQ(headers.get(foo)->value().getStringView(), "not-empty"); + EXPECT_EQ(headers.get(foo)[0]->value().getStringView(), "not-empty"); // Use setCopy with inline headers both indirectly and directly. headers.clear(); @@ -869,14 +868,14 @@ TEST_P(HeaderMapImplTest, AddCopy) { std::unique_ptr lcKeyPtr(new LowerCaseString("hello")); headers.addCopy(*lcKeyPtr, "world"); - const HeaderString& value = headers.get(*lcKeyPtr)->value(); + const HeaderString& value = headers.get(*lcKeyPtr)[0]->value(); EXPECT_EQ("world", value.getStringView()); EXPECT_EQ(5UL, value.size()); lcKeyPtr.reset(); - const HeaderString& value2 = headers.get(LowerCaseString("hello"))->value(); + const HeaderString& value2 = headers.get(LowerCaseString("hello"))[0]->value(); EXPECT_EQ("world", value2.getStringView()); EXPECT_EQ(5UL, value2.size()); @@ -898,14 +897,14 @@ TEST_P(HeaderMapImplTest, AddCopy) { headers.addCopy(*lcKeyPtr, 42); - const HeaderString& value3 = headers.get(*lcKeyPtr)->value(); + const HeaderString& value3 = headers.get(*lcKeyPtr)[0]->value(); EXPECT_EQ("42", value3.getStringView()); EXPECT_EQ(2UL, value3.size()); lcKeyPtr.reset(); - const HeaderString& value4 = headers.get(LowerCaseString("hello"))->value(); + const HeaderString& value4 = headers.get(LowerCaseString("hello"))[0]->value(); EXPECT_EQ("42", value4.getStringView()); EXPECT_EQ(2UL, value4.size()); @@ -915,22 +914,22 @@ TEST_P(HeaderMapImplTest, AddCopy) { LowerCaseString lcKey3(std::string("he") + "ll" + "o"); EXPECT_STREQ("hello", lcKey3.get().c_str()); - EXPECT_EQ("42", headers.get(lcKey3)->value().getStringView()); - EXPECT_EQ(2UL, headers.get(lcKey3)->value().size()); + EXPECT_EQ("42", headers.get(lcKey3)[0]->value().getStringView()); + EXPECT_EQ(2UL, headers.get(lcKey3)[0]->value().size()); LowerCaseString envoy_retry_on("x-envoy-retry-on"); headers.addCopy(envoy_retry_on, "max-age=1345"); - EXPECT_EQ("max-age=1345", headers.get(envoy_retry_on)->value().getStringView()); + EXPECT_EQ("max-age=1345", headers.get(envoy_retry_on)[0]->value().getStringView()); EXPECT_EQ("max-age=1345", headers.getEnvoyRetryOnValue()); headers.addCopy(envoy_retry_on, "public"); - EXPECT_EQ("max-age=1345,public", headers.get(envoy_retry_on)->value().getStringView()); + EXPECT_EQ("max-age=1345,public", headers.get(envoy_retry_on)[0]->value().getStringView()); headers.addCopy(envoy_retry_on, ""); - EXPECT_EQ("max-age=1345,public", headers.get(envoy_retry_on)->value().getStringView()); + EXPECT_EQ("max-age=1345,public", headers.get(envoy_retry_on)[0]->value().getStringView()); headers.addCopy(envoy_retry_on, 123); - EXPECT_EQ("max-age=1345,public,123", headers.get(envoy_retry_on)->value().getStringView()); + EXPECT_EQ("max-age=1345,public,123", headers.get(envoy_retry_on)[0]->value().getStringView()); headers.addCopy(envoy_retry_on, std::numeric_limits::max()); EXPECT_EQ("max-age=1345,public,123,18446744073709551615", - headers.get(envoy_retry_on)->value().getStringView()); + headers.get(envoy_retry_on)[0]->value().getStringView()); } TEST_P(HeaderMapImplTest, Equality) { @@ -950,7 +949,7 @@ TEST_P(HeaderMapImplTest, LargeCharInHeader) { LowerCaseString static_key("\x90hello"); std::string ref_value("value"); headers.addReference(static_key, ref_value); - EXPECT_EQ("value", headers.get(static_key)->value().getStringView()); + EXPECT_EQ("value", headers.get(static_key)[0]->value().getStringView()); } TEST_P(HeaderMapImplTest, Iterate) { @@ -996,9 +995,9 @@ TEST_P(HeaderMapImplTest, IterateReverse) { TEST_P(HeaderMapImplTest, Get) { { auto headers = TestRequestHeaderMapImpl({{Headers::get().Path.get(), "/"}, {"hello", "world"}}); - EXPECT_EQ("/", headers.get(LowerCaseString(":path"))->value().getStringView()); - EXPECT_EQ("world", headers.get(LowerCaseString("hello"))->value().getStringView()); - EXPECT_EQ(nullptr, headers.get(LowerCaseString("foo"))); + EXPECT_EQ("/", headers.get(LowerCaseString(":path"))[0]->value().getStringView()); + EXPECT_EQ("world", headers.get(LowerCaseString("hello"))[0]->value().getStringView()); + EXPECT_TRUE(headers.get(LowerCaseString("foo")).empty()); } { @@ -1006,11 +1005,11 @@ TEST_P(HeaderMapImplTest, Get) { // There is not HeaderMap method to set a header and copy both the key and value. const LowerCaseString path(":path"); headers.setReferenceKey(path, "/new_path"); - EXPECT_EQ("/new_path", headers.get(LowerCaseString(":path"))->value().getStringView()); + EXPECT_EQ("/new_path", headers.get(LowerCaseString(":path"))[0]->value().getStringView()); const LowerCaseString foo("hello"); headers.setReferenceKey(foo, "world2"); - EXPECT_EQ("world2", headers.get(foo)->value().getStringView()); - EXPECT_EQ(nullptr, headers.get(LowerCaseString("foo"))); + EXPECT_EQ("world2", headers.get(foo)[0]->value().getStringView()); + EXPECT_TRUE(headers.get(LowerCaseString("foo")).empty()); } } @@ -1018,9 +1017,9 @@ TEST_P(HeaderMapImplTest, CreateHeaderMapFromIterator) { std::vector> iter_headers{ {LowerCaseString(Headers::get().Path), "/"}, {LowerCaseString("hello"), "world"}}; auto headers = createHeaderMap(iter_headers.cbegin(), iter_headers.cend()); - EXPECT_EQ("/", headers->get(LowerCaseString(":path"))->value().getStringView()); - EXPECT_EQ("world", headers->get(LowerCaseString("hello"))->value().getStringView()); - EXPECT_EQ(nullptr, headers->get(LowerCaseString("foo"))); + EXPECT_EQ("/", headers->get(LowerCaseString(":path"))[0]->value().getStringView()); + EXPECT_EQ("world", headers->get(LowerCaseString("hello"))[0]->value().getStringView()); + EXPECT_TRUE(headers->get(LowerCaseString("foo")).empty()); } TEST_P(HeaderMapImplTest, TestHeaderList) { @@ -1048,7 +1047,7 @@ TEST_P(HeaderMapImplTest, TestAppendHeader) { LowerCaseString foo("key1"); headers.addCopy(foo, "some;"); headers.appendCopy(foo, "test"); - EXPECT_EQ(headers.get(foo)->value().getStringView(), "some;,test"); + EXPECT_EQ(headers.get(foo)[0]->value().getStringView(), "some;,test"); } // Test appending to an empty string. @@ -1056,7 +1055,7 @@ TEST_P(HeaderMapImplTest, TestAppendHeader) { TestRequestHeaderMapImpl headers; LowerCaseString key2("key2"); headers.appendCopy(key2, "my tag data"); - EXPECT_EQ(headers.get(key2)->value().getStringView(), "my tag data"); + EXPECT_EQ(headers.get(key2)[0]->value().getStringView(), "my tag data"); } // Test empty data case. @@ -1065,7 +1064,7 @@ TEST_P(HeaderMapImplTest, TestAppendHeader) { LowerCaseString key3("key3"); headers.addCopy(key3, "empty"); headers.appendCopy(key3, ""); - EXPECT_EQ(headers.get(key3)->value().getStringView(), "empty"); + EXPECT_EQ(headers.get(key3)[0]->value().getStringView(), "empty"); } // Regression test for appending to an empty string with a short string, then // setting integer. @@ -1257,13 +1256,13 @@ TEST_P(HeaderMapImplTest, TestRequestHeaderMapImplCopy) { TestRequestHeaderMapImpl foo; foo.addCopy(LowerCaseString("foo"), "bar"); auto headers = std::make_unique(foo); - EXPECT_EQ("bar", headers->get(LowerCaseString("foo"))->value().getStringView()); + EXPECT_EQ("bar", headers->get(LowerCaseString("foo"))[0]->value().getStringView()); TestRequestHeaderMapImpl baz{{"foo", "baz"}}; baz = *headers; - EXPECT_EQ("bar", baz.get(LowerCaseString("foo"))->value().getStringView()); + EXPECT_EQ("bar", baz.get(LowerCaseString("foo"))[0]->value().getStringView()); const TestRequestHeaderMapImpl& baz2 = baz; baz = baz2; - EXPECT_EQ("bar", baz.get(LowerCaseString("foo"))->value().getStringView()); + EXPECT_EQ("bar", baz.get(LowerCaseString("foo"))[0]->value().getStringView()); } // Make sure 'host' -> ':authority' auto translation only occurs for request headers. @@ -1299,12 +1298,12 @@ TEST_P(HeaderMapImplTest, ClearHeaderMap) { // Add random header and then clear. headers.addReference(static_key, ref_value); - EXPECT_EQ("value", headers.get(static_key)->value().getStringView()); - EXPECT_TRUE(headers.get(static_key)->value().isReference()); + EXPECT_EQ("value", headers.get(static_key)[0]->value().getStringView()); + EXPECT_TRUE(headers.get(static_key)[0]->value().isReference()); EXPECT_EQ(1UL, headers.size()); EXPECT_FALSE(headers.empty()); headers.clear(); - EXPECT_EQ(nullptr, headers.get(static_key)); + EXPECT_TRUE(headers.get(static_key).empty()); EXPECT_EQ(0UL, headers.size()); EXPECT_EQ(headers.byteSize(), 0); EXPECT_TRUE(headers.empty()); diff --git a/test/common/http/header_utility_test.cc b/test/common/http/header_utility_test.cc index 068eb67eec8b..47c39a36311e 100644 --- a/test/common/http/header_utility_test.cc +++ b/test/common/http/header_utility_test.cc @@ -249,27 +249,6 @@ invert_match: true EXPECT_EQ(true, header_data.invert_match_); } -TEST(HeaderDataConstructorTest, GetAllOfHeader) { - TestRequestHeaderMapImpl headers{ - {"foo", "val1"}, {"bar", "bar2"}, {"foo", "eep, bar"}, {"foo", ""}}; - - std::vector foo_out; - Http::HeaderUtility::getAllOfHeader(headers, "foo", foo_out); - ASSERT_EQ(foo_out.size(), 3); - ASSERT_EQ(foo_out[0], "val1"); - ASSERT_EQ(foo_out[1], "eep, bar"); - ASSERT_EQ(foo_out[2], ""); - - std::vector bar_out; - Http::HeaderUtility::getAllOfHeader(headers, "bar", bar_out); - ASSERT_EQ(bar_out.size(), 1); - ASSERT_EQ(bar_out[0], "bar2"); - - std::vector eep_out; - Http::HeaderUtility::getAllOfHeader(headers, "eep", eep_out); - ASSERT_EQ(eep_out.size(), 0); -} - TEST(MatchHeadersTest, MayMatchOneOrMoreRequestHeader) { TestRequestHeaderMapImpl headers{{"some-header", "a"}, {"other-header", "b"}}; @@ -668,7 +647,7 @@ TEST(HeaderAddTest, HeaderAdd) { headers_to_add.iterate([&headers](const Http::HeaderEntry& entry) -> Http::HeaderMap::Iterate { Http::LowerCaseString lower_key{std::string(entry.key().getStringView())}; - EXPECT_EQ(entry.value().getStringView(), headers.get(lower_key)->value().getStringView()); + EXPECT_EQ(entry.value().getStringView(), headers.get(lower_key)[0]->value().getStringView()); return Http::HeaderMap::Iterate::Continue; }); } diff --git a/test/common/http/request_id_extension_uuid_impl_test.cc b/test/common/http/request_id_extension_uuid_impl_test.cc index 0b471c3a88cf..a975a8a24d69 100644 --- a/test/common/http/request_id_extension_uuid_impl_test.cc +++ b/test/common/http/request_id_extension_uuid_impl_test.cc @@ -48,7 +48,7 @@ TEST(UUIDRequestIDExtensionTest, PreserveRequestIDInResponse) { TestResponseHeaderMapImpl response_headers; uuid_utils.setInResponse(response_headers, request_headers); - EXPECT_EQ(nullptr, response_headers.get(Headers::get().RequestId)); + EXPECT_TRUE(response_headers.get(Headers::get().RequestId).empty()); request_headers.setRequestId("some-request-id"); uuid_utils.setInResponse(response_headers, request_headers); diff --git a/test/common/local_reply/local_reply_test.cc b/test/common/local_reply/local_reply_test.cc index c54e38c31c03..e635bfea2d43 100644 --- a/test/common/local_reply/local_reply_test.cc +++ b/test/common/local_reply/local_reply_test.cc @@ -329,11 +329,10 @@ TEST_F(LocalReplyTest, TestHeaderAddition) { EXPECT_EQ(response_headers_.get_("foo-1"), "bar1"); EXPECT_EQ(response_headers_.get_("foo-2"), "override-bar2"); - std::vector out; - Http::HeaderUtility::getAllOfHeader(response_headers_, "foo-3", out); + const auto out = response_headers_.get(Http::LowerCaseString("foo-3")); ASSERT_EQ(out.size(), 2); - ASSERT_EQ(out[0], "bar3"); - ASSERT_EQ(out[1], "append-bar3"); + ASSERT_EQ(out[0]->value().getStringView(), "bar3"); + ASSERT_EQ(out[1]->value().getStringView(), "append-bar3"); } TEST_F(LocalReplyTest, TestMapperWithContentType) { diff --git a/test/common/router/header_formatter_test.cc b/test/common/router/header_formatter_test.cc index d56a890ed427..f045b12d4fda 100644 --- a/test/common/router/header_formatter_test.cc +++ b/test/common/router/header_formatter_test.cc @@ -1346,11 +1346,10 @@ response_headers_to_remove: ["x-nope"] // Per https://github.com/envoyproxy/envoy/issues/7488 make sure we don't // combine set-cookie headers - std::vector out; - Http::HeaderUtility::getAllOfHeader(header_map, "set-cookie", out); + const auto out = header_map.get(Http::LowerCaseString("set-cookie")); ASSERT_EQ(out.size(), 2); - ASSERT_EQ(out[0], "foo"); - ASSERT_EQ(out[1], "bar"); + ASSERT_EQ(out[0]->value().getStringView(), "foo"); + ASSERT_EQ(out[1]->value().getStringView(), "bar"); } TEST(HeaderParserTest, EvaluateRequestHeadersRemoveBeforeAdd) { diff --git a/test/common/router/router_test.cc b/test/common/router/router_test.cc index f739a2c857ee..6b893358a704 100644 --- a/test/common/router/router_test.cc +++ b/test/common/router/router_test.cc @@ -663,8 +663,9 @@ TEST_F(RouterTest, AddCookie) { EXPECT_CALL(callbacks_, encodeHeaders_(_, _)) .WillOnce(Invoke([&](const Http::HeaderMap& headers, const bool) -> void { - EXPECT_EQ(std::string{headers.get(Http::Headers::get().SetCookie)->value().getStringView()}, - "foo=\"" + cookie_value + "\"; Max-Age=1337; HttpOnly"); + EXPECT_EQ( + std::string{headers.get(Http::Headers::get().SetCookie)[0]->value().getStringView()}, + "foo=\"" + cookie_value + "\"; Max-Age=1337; HttpOnly"); })); expectResponseTimerCreate(); @@ -714,8 +715,9 @@ TEST_F(RouterTest, AddCookieNoDuplicate) { EXPECT_CALL(callbacks_, encodeHeaders_(_, _)) .WillOnce(Invoke([&](const Http::HeaderMap& headers, const bool) -> void { - EXPECT_EQ(std::string{headers.get(Http::Headers::get().SetCookie)->value().getStringView()}, - "foo=baz"); + EXPECT_EQ( + std::string{headers.get(Http::Headers::get().SetCookie)[0]->value().getStringView()}, + "foo=baz"); })); expectResponseTimerCreate(); @@ -970,7 +972,7 @@ TEST_F(RouterTest, EnvoyUpstreamServiceTime) { EXPECT_CALL(cm_.conn_pool_.host_->outlier_detector_, putHttpResponseCode(200)); EXPECT_CALL(callbacks_, encodeHeaders_(_, true)) .WillOnce(Invoke([](Http::HeaderMap& headers, bool) { - EXPECT_NE(nullptr, headers.get(Http::Headers::get().EnvoyUpstreamServiceTime)); + EXPECT_FALSE(headers.get(Http::Headers::get().EnvoyUpstreamServiceTime).empty()); })); response_decoder->decodeHeaders(std::move(response_headers), true); EXPECT_TRUE(verifyHostUpstreamStats(1, 0)); @@ -1239,10 +1241,10 @@ void RouterTestBase::testAppendCluster(absl::optional clu EXPECT_CALL(cm_.conn_pool_.host_->outlier_detector_, putHttpResponseCode(200)); EXPECT_CALL(callbacks_, encodeHeaders_(_, true)) .WillOnce(Invoke([&cluster_header_name](Http::HeaderMap& headers, bool) { - const Http::HeaderEntry* cluster_header = + const auto cluster_header = headers.get(cluster_header_name.value_or(Http::Headers::get().EnvoyCluster)); - EXPECT_NE(nullptr, cluster_header); - EXPECT_EQ("fake_cluster", cluster_header->value().getStringView()); + EXPECT_FALSE(cluster_header.empty()); + EXPECT_EQ("fake_cluster", cluster_header[0]->value().getStringView()); })); response_decoder->decodeHeaders(std::move(response_headers), true); EXPECT_TRUE(verifyHostUpstreamStats(1, 0)); @@ -1297,15 +1299,15 @@ void RouterTestBase::testAppendUpstreamHost( EXPECT_CALL(callbacks_, encodeHeaders_(_, true)) .WillOnce(Invoke([&hostname_header_name, &host_address_header_name](Http::HeaderMap& headers, bool) { - const Http::HeaderEntry* hostname_header = + const auto hostname_header = headers.get(hostname_header_name.value_or(Http::Headers::get().EnvoyUpstreamHostname)); - EXPECT_NE(nullptr, hostname_header); - EXPECT_EQ("scooby.doo", hostname_header->value().getStringView()); + EXPECT_FALSE(hostname_header.empty()); + EXPECT_EQ("scooby.doo", hostname_header[0]->value().getStringView()); - const Http::HeaderEntry* host_address_header = headers.get( + const auto host_address_header = headers.get( host_address_header_name.value_or(Http::Headers::get().EnvoyUpstreamHostAddress)); - EXPECT_NE(nullptr, host_address_header); - EXPECT_EQ("10.0.0.5:9211", host_address_header->value().getStringView()); + EXPECT_FALSE(host_address_header.empty()); + EXPECT_EQ("10.0.0.5:9211", host_address_header[0]->value().getStringView()); })); response_decoder->decodeHeaders(std::move(response_headers), true); EXPECT_TRUE(verifyHostUpstreamStats(1, 0)); @@ -1430,7 +1432,7 @@ TEST_F(RouterTestSuppressEnvoyHeaders, EnvoyUpstreamServiceTime) { {":status", "200"}, {"x-envoy-upstream-service-time", "0"}}; EXPECT_CALL(callbacks_, encodeHeaders_(_, true)) .WillOnce(Invoke([](Http::HeaderMap& headers, bool) { - EXPECT_EQ(nullptr, headers.get(Http::Headers::get().EnvoyUpstreamServiceTime)); + EXPECT_TRUE(headers.get(Http::Headers::get().EnvoyUpstreamServiceTime).empty()); })); response_decoder->decodeHeaders(std::move(response_headers), true); EXPECT_TRUE(verifyHostUpstreamStats(1, 0)); diff --git a/test/common/upstream/health_checker_impl_test.cc b/test/common/upstream/health_checker_impl_test.cc index 321eeaa269d4..a3c0cf04b1cb 100644 --- a/test/common/upstream/health_checker_impl_test.cc +++ b/test/common/upstream/health_checker_impl_test.cc @@ -1237,27 +1237,28 @@ TEST_F(HttpHealthCheckerImplTest, SuccessServiceCheckWithAdditionalHeaders) { EXPECT_CALL(*test_sessions_[0]->timeout_timer_, enableTimer(_, _)); EXPECT_CALL(test_sessions_[0]->request_encoder_, encodeHeaders(_, true)) .WillRepeatedly(Invoke([&](const Http::RequestHeaderMap& headers, bool) { - EXPECT_EQ(headers.get(header_ok)->value().getStringView(), value_ok); - EXPECT_EQ(headers.get(header_cool)->value().getStringView(), value_cool); - EXPECT_EQ(headers.get(header_awesome)->value().getStringView(), value_awesome); + EXPECT_EQ(headers.get(header_ok)[0]->value().getStringView(), value_ok); + EXPECT_EQ(headers.get(header_cool)[0]->value().getStringView(), value_cool); + EXPECT_EQ(headers.get(header_awesome)[0]->value().getStringView(), value_awesome); EXPECT_EQ(headers.getUserAgentValue(), value_user_agent); - EXPECT_EQ(headers.get(upstream_metadata)->value().getStringView(), value_upstream_metadata); + EXPECT_EQ(headers.get(upstream_metadata)[0]->value().getStringView(), + value_upstream_metadata); - EXPECT_EQ(headers.get(protocol)->value().getStringView(), value_protocol); - EXPECT_EQ(headers.get(downstream_remote_address)->value().getStringView(), + EXPECT_EQ(headers.get(protocol)[0]->value().getStringView(), value_protocol); + EXPECT_EQ(headers.get(downstream_remote_address)[0]->value().getStringView(), value_downstream_remote_address); - EXPECT_EQ(headers.get(downstream_remote_address_without_port)->value().getStringView(), + EXPECT_EQ(headers.get(downstream_remote_address_without_port)[0]->value().getStringView(), value_downstream_remote_address_without_port); - EXPECT_EQ(headers.get(downstream_local_address)->value().getStringView(), + EXPECT_EQ(headers.get(downstream_local_address)[0]->value().getStringView(), value_downstream_local_address); - EXPECT_EQ(headers.get(downstream_local_address_without_port)->value().getStringView(), + EXPECT_EQ(headers.get(downstream_local_address_without_port)[0]->value().getStringView(), value_downstream_local_address_without_port); Envoy::DateFormatter date_formatter("%s.%9f"); std::string current_start_time = date_formatter.fromTime(dispatcher_.timeSource().systemTime()); - EXPECT_EQ(headers.get(start_time)->value().getStringView(), current_start_time); + EXPECT_EQ(headers.get(start_time)[0]->value().getStringView(), current_start_time); })); health_checker_->start(); diff --git a/test/extensions/common/aws/signer_impl_test.cc b/test/extensions/common/aws/signer_impl_test.cc index 676e6fbd63e7..cc4fb856b5de 100644 --- a/test/extensions/common/aws/signer_impl_test.cc +++ b/test/extensions/common/aws/signer_impl_test.cc @@ -56,8 +56,9 @@ class SignerImplTest : public testing::Test { "SignedHeaders=host;x-amz-content-sha256;x-amz-date, " "Signature={}", service_name, signature), - headers.get(Http::CustomHeaders::get().Authorization)->value().getStringView()); - EXPECT_EQ(payload, headers.get(SignatureHeaders::get().ContentSha256)->value().getStringView()); + headers.get(Http::CustomHeaders::get().Authorization)[0]->value().getStringView()); + EXPECT_EQ(payload, + headers.get(SignatureHeaders::get().ContentSha256)[0]->value().getStringView()); } NiceMock* credentials_provider_; @@ -73,7 +74,7 @@ class SignerImplTest : public testing::Test { TEST_F(SignerImplTest, AnonymousCredentials) { EXPECT_CALL(*credentials_provider_, getCredentials()).WillOnce(Return(Credentials())); signer_.sign(*message_); - EXPECT_EQ(nullptr, message_->headers().get(Http::CustomHeaders::get().Authorization)); + EXPECT_TRUE(message_->headers().get(Http::CustomHeaders::get().Authorization).empty()); } // HTTP :method header is required @@ -81,7 +82,7 @@ TEST_F(SignerImplTest, MissingMethodException) { EXPECT_CALL(*credentials_provider_, getCredentials()).WillOnce(Return(credentials_)); EXPECT_THROW_WITH_MESSAGE(signer_.sign(*message_), EnvoyException, "Message is missing :method header"); - EXPECT_EQ(nullptr, message_->headers().get(Http::CustomHeaders::get().Authorization)); + EXPECT_TRUE(message_->headers().get(Http::CustomHeaders::get().Authorization).empty()); } // HTTP :path header is required @@ -90,7 +91,7 @@ TEST_F(SignerImplTest, MissingPathException) { addMethod("GET"); EXPECT_THROW_WITH_MESSAGE(signer_.sign(*message_), EnvoyException, "Message is missing :path header"); - EXPECT_EQ(nullptr, message_->headers().get(Http::CustomHeaders::get().Authorization)); + EXPECT_TRUE(message_->headers().get(Http::CustomHeaders::get().Authorization).empty()); } // Verify we sign the date header @@ -99,14 +100,16 @@ TEST_F(SignerImplTest, SignDateHeader) { addMethod("GET"); addPath("/"); signer_.sign(*message_); - EXPECT_NE(nullptr, message_->headers().get(SignatureHeaders::get().ContentSha256)); + EXPECT_FALSE(message_->headers().get(SignatureHeaders::get().ContentSha256).empty()); EXPECT_EQ("20180102T030400Z", - message_->headers().get(SignatureHeaders::get().Date)->value().getStringView()); - EXPECT_EQ( - "AWS4-HMAC-SHA256 Credential=akid/20180102/region/service/aws4_request, " - "SignedHeaders=x-amz-content-sha256;x-amz-date, " - "Signature=4ee6aa9355259c18133f150b139ea9aeb7969c9408ad361b2151f50a516afe42", - message_->headers().get(Http::CustomHeaders::get().Authorization)->value().getStringView()); + message_->headers().get(SignatureHeaders::get().Date)[0]->value().getStringView()); + EXPECT_EQ("AWS4-HMAC-SHA256 Credential=akid/20180102/region/service/aws4_request, " + "SignedHeaders=x-amz-content-sha256;x-amz-date, " + "Signature=4ee6aa9355259c18133f150b139ea9aeb7969c9408ad361b2151f50a516afe42", + message_->headers() + .get(Http::CustomHeaders::get().Authorization)[0] + ->value() + .getStringView()); } // Verify we sign the security token header if the token is present in the credentials @@ -117,12 +120,14 @@ TEST_F(SignerImplTest, SignSecurityTokenHeader) { signer_.sign(*message_); EXPECT_EQ( "token", - message_->headers().get(SignatureHeaders::get().SecurityToken)->value().getStringView()); - EXPECT_EQ( - "AWS4-HMAC-SHA256 Credential=akid/20180102/region/service/aws4_request, " - "SignedHeaders=x-amz-content-sha256;x-amz-date;x-amz-security-token, " - "Signature=1d42526aabf7d8b6d7d33d9db43b03537300cc7e6bb2817e349749e0a08f5b5e", - message_->headers().get(Http::CustomHeaders::get().Authorization)->value().getStringView()); + message_->headers().get(SignatureHeaders::get().SecurityToken)[0]->value().getStringView()); + EXPECT_EQ("AWS4-HMAC-SHA256 Credential=akid/20180102/region/service/aws4_request, " + "SignedHeaders=x-amz-content-sha256;x-amz-date;x-amz-security-token, " + "Signature=1d42526aabf7d8b6d7d33d9db43b03537300cc7e6bb2817e349749e0a08f5b5e", + message_->headers() + .get(Http::CustomHeaders::get().Authorization)[0] + ->value() + .getStringView()); } // Verify we sign the content header as the hashed empty string if the body is empty @@ -133,12 +138,14 @@ TEST_F(SignerImplTest, SignEmptyContentHeader) { signer_.sign(*message_, true); EXPECT_EQ( SignatureConstants::get().HashedEmptyString, - message_->headers().get(SignatureHeaders::get().ContentSha256)->value().getStringView()); - EXPECT_EQ( - "AWS4-HMAC-SHA256 Credential=akid/20180102/region/service/aws4_request, " - "SignedHeaders=x-amz-content-sha256;x-amz-date, " - "Signature=4ee6aa9355259c18133f150b139ea9aeb7969c9408ad361b2151f50a516afe42", - message_->headers().get(Http::CustomHeaders::get().Authorization)->value().getStringView()); + message_->headers().get(SignatureHeaders::get().ContentSha256)[0]->value().getStringView()); + EXPECT_EQ("AWS4-HMAC-SHA256 Credential=akid/20180102/region/service/aws4_request, " + "SignedHeaders=x-amz-content-sha256;x-amz-date, " + "Signature=4ee6aa9355259c18133f150b139ea9aeb7969c9408ad361b2151f50a516afe42", + message_->headers() + .get(Http::CustomHeaders::get().Authorization)[0] + ->value() + .getStringView()); } // Verify we sign the content header correctly when we have a body @@ -150,12 +157,14 @@ TEST_F(SignerImplTest, SignContentHeader) { signer_.sign(*message_, true); EXPECT_EQ( "937e8d5fbb48bd4949536cd65b8d35c426b80d2f830c5c308e2cdec422ae2244", - message_->headers().get(SignatureHeaders::get().ContentSha256)->value().getStringView()); - EXPECT_EQ( - "AWS4-HMAC-SHA256 Credential=akid/20180102/region/service/aws4_request, " - "SignedHeaders=x-amz-content-sha256;x-amz-date, " - "Signature=4eab89c36f45f2032d6010ba1adab93f8510ddd6afe540821f3a05bb0253e27b", - message_->headers().get(Http::CustomHeaders::get().Authorization)->value().getStringView()); + message_->headers().get(SignatureHeaders::get().ContentSha256)[0]->value().getStringView()); + EXPECT_EQ("AWS4-HMAC-SHA256 Credential=akid/20180102/region/service/aws4_request, " + "SignedHeaders=x-amz-content-sha256;x-amz-date, " + "Signature=4eab89c36f45f2032d6010ba1adab93f8510ddd6afe540821f3a05bb0253e27b", + message_->headers() + .get(Http::CustomHeaders::get().Authorization)[0] + ->value() + .getStringView()); } // Verify we sign some extra headers @@ -167,11 +176,13 @@ TEST_F(SignerImplTest, SignExtraHeaders) { addHeader("b", "b_value"); addHeader("c", "c_value"); signer_.sign(*message_); - EXPECT_EQ( - "AWS4-HMAC-SHA256 Credential=akid/20180102/region/service/aws4_request, " - "SignedHeaders=a;b;c;x-amz-content-sha256;x-amz-date, " - "Signature=0940025fcecfef5d7ee30e0a26a0957e116560e374878cd86ef4316c53ae9e81", - message_->headers().get(Http::CustomHeaders::get().Authorization)->value().getStringView()); + EXPECT_EQ("AWS4-HMAC-SHA256 Credential=akid/20180102/region/service/aws4_request, " + "SignedHeaders=a;b;c;x-amz-content-sha256;x-amz-date, " + "Signature=0940025fcecfef5d7ee30e0a26a0957e116560e374878cd86ef4316c53ae9e81", + message_->headers() + .get(Http::CustomHeaders::get().Authorization)[0] + ->value() + .getStringView()); } // Verify signing a host header @@ -181,11 +192,13 @@ TEST_F(SignerImplTest, SignHostHeader) { addPath("/"); addHeader("host", "www.example.com"); signer_.sign(*message_); - EXPECT_EQ( - "AWS4-HMAC-SHA256 Credential=akid/20180102/region/service/aws4_request, " - "SignedHeaders=host;x-amz-content-sha256;x-amz-date, " - "Signature=d9fd9be575a254c924d843964b063d770181d938ae818f5b603ef0575a5ce2cd", - message_->headers().get(Http::CustomHeaders::get().Authorization)->value().getStringView()); + EXPECT_EQ("AWS4-HMAC-SHA256 Credential=akid/20180102/region/service/aws4_request, " + "SignedHeaders=host;x-amz-content-sha256;x-amz-date, " + "Signature=d9fd9be575a254c924d843964b063d770181d938ae818f5b603ef0575a5ce2cd", + message_->headers() + .get(Http::CustomHeaders::get().Authorization)[0] + ->value() + .getStringView()); } // Verify signing headers for services. diff --git a/test/extensions/filters/common/ext_authz/ext_authz_http_impl_test.cc b/test/extensions/filters/common/ext_authz/ext_authz_http_impl_test.cc index 23b396f6b004..14e0dd4eb955 100644 --- a/test/extensions/filters/common/ext_authz/ext_authz_http_impl_test.cc +++ b/test/extensions/filters/common/ext_authz/ext_authz_http_impl_test.cc @@ -265,22 +265,22 @@ TEST_F(ExtAuthzHttpClientTest, AllowedRequestHeadersPrefix) { {regexFood.get(), "food"}, {regexFool.get(), "fool"}}); - EXPECT_EQ(message_ptr->headers().get(Http::Headers::get().ContentType), nullptr); - const auto* x_squash = message_ptr->headers().get(Http::Headers::get().XSquashDebug); - ASSERT_NE(x_squash, nullptr); - EXPECT_EQ(x_squash->value().getStringView(), "foo"); - - const auto* x_content_type = message_ptr->headers().get(Http::Headers::get().XContentTypeOptions); - ASSERT_NE(x_content_type, nullptr); - EXPECT_EQ(x_content_type->value().getStringView(), "foobar"); - - const auto* food = message_ptr->headers().get(regexFood); - ASSERT_NE(food, nullptr); - EXPECT_EQ(food->value().getStringView(), "food"); - - const auto* fool = message_ptr->headers().get(regexFool); - ASSERT_NE(fool, nullptr); - EXPECT_EQ(fool->value().getStringView(), "fool"); + EXPECT_TRUE(message_ptr->headers().get(Http::Headers::get().ContentType).empty()); + const auto x_squash = message_ptr->headers().get(Http::Headers::get().XSquashDebug); + ASSERT_FALSE(x_squash.empty()); + EXPECT_EQ(x_squash[0]->value().getStringView(), "foo"); + + const auto x_content_type = message_ptr->headers().get(Http::Headers::get().XContentTypeOptions); + ASSERT_FALSE(x_content_type.empty()); + EXPECT_EQ(x_content_type[0]->value().getStringView(), "foobar"); + + const auto food = message_ptr->headers().get(regexFood); + ASSERT_FALSE(food.empty()); + EXPECT_EQ(food[0]->value().getStringView(), "food"); + + const auto fool = message_ptr->headers().get(regexFool); + ASSERT_FALSE(fool.empty()); + EXPECT_EQ(fool[0]->value().getStringView(), "fool"); } // Verify client response when authorization server returns a 200 OK. diff --git a/test/extensions/filters/common/ext_authz/test_common.h b/test/extensions/filters/common/ext_authz/test_common.h index 0520394f46a4..efbbc8e411ec 100644 --- a/test/extensions/filters/common/ext_authz/test_common.h +++ b/test/extensions/filters/common/ext_authz/test_common.h @@ -121,7 +121,7 @@ MATCHER_P(AuthzOkResponse, response, "") { } MATCHER_P(ContainsPairAsHeader, pair, "") { - return arg->headers().get(pair.first)->value().getStringView() == pair.second; + return arg->headers().get(pair.first)[0]->value().getStringView() == pair.second; } } // namespace ExtAuthz diff --git a/test/extensions/filters/http/aws_lambda/aws_lambda_filter_integration_test.cc b/test/extensions/filters/http/aws_lambda/aws_lambda_filter_integration_test.cc index c752f4ca651b..a65c4425ac03 100644 --- a/test/extensions/filters/http/aws_lambda/aws_lambda_filter_integration_test.cc +++ b/test/extensions/filters/http/aws_lambda/aws_lambda_filter_integration_test.cc @@ -122,13 +122,13 @@ class AwsLambdaFilterIntegrationTest : public testing::TestWithParamcomplete()); // verify headers - expected_response_headers.iterate( - [actual_headers = &response->headers()](const Http::HeaderEntry& expected_entry) { - const auto* actual_entry = actual_headers->get( - Http::LowerCaseString(std::string(expected_entry.key().getStringView()))); - EXPECT_EQ(actual_entry->value().getStringView(), expected_entry.value().getStringView()); - return Http::HeaderMap::Iterate::Continue; - }); + expected_response_headers.iterate([actual_headers = &response->headers()]( + const Http::HeaderEntry& expected_entry) { + const auto actual_entry = actual_headers->get( + Http::LowerCaseString(std::string(expected_entry.key().getStringView()))); + EXPECT_EQ(actual_entry[0]->value().getStringView(), expected_entry.value().getStringView()); + return Http::HeaderMap::Iterate::Continue; + }); // verify cookies if we have any if (!expected_response_cookies.empty()) { diff --git a/test/extensions/filters/http/aws_lambda/aws_lambda_filter_test.cc b/test/extensions/filters/http/aws_lambda/aws_lambda_filter_test.cc index ab0cf4c2c900..bcc46b3dc5e3 100644 --- a/test/extensions/filters/http/aws_lambda/aws_lambda_filter_test.cc +++ b/test/extensions/filters/http/aws_lambda/aws_lambda_filter_test.cc @@ -517,11 +517,8 @@ TEST_F(AwsLambdaFilterTest, EncodeDataJsonModeTransformToHttp) { ASSERT_NE(nullptr, headers.Status()); EXPECT_EQ("201", headers.getStatusValue()); - EXPECT_EQ(nullptr, headers.get(Http::LowerCaseString(":other"))); - - const auto* custom_header = headers.get(Http::LowerCaseString("x-awesome-header")); - EXPECT_NE(custom_header, nullptr); - EXPECT_EQ("awesome value", custom_header->value().getStringView()); + EXPECT_FALSE(headers.has(":other")); + EXPECT_EQ("awesome value", headers.get_("x-awesome-header")); std::vector cookies; headers.iterate([&cookies](const Http::HeaderEntry& entry) { diff --git a/test/extensions/filters/http/cache/cache_filter_integration_test.cc b/test/extensions/filters/http/cache/cache_filter_integration_test.cc index 7630e0c44fdb..f8fb6a830960 100644 --- a/test/extensions/filters/http/cache/cache_filter_integration_test.cc +++ b/test/extensions/filters/http/cache/cache_filter_integration_test.cc @@ -72,7 +72,7 @@ TEST_P(CacheIntegrationTest, MissInsertHit) { response_decoder->waitForEndStream(); EXPECT_TRUE(response_decoder->complete()); EXPECT_THAT(response_decoder->headers(), IsSupersetOfHeaders(response_headers)); - EXPECT_EQ(response_decoder->headers().get(Http::Headers::get().Age), nullptr); + EXPECT_TRUE(response_decoder->headers().get(Http::Headers::get().Age).empty()); EXPECT_EQ(response_decoder->body(), response_body); EXPECT_THAT(waitForAccessLog(access_log_name_), testing::HasSubstr("- via_upstream")); } @@ -129,7 +129,7 @@ TEST_P(CacheIntegrationTest, ExpiredValidated) { response_decoder->waitForEndStream(); EXPECT_TRUE(response_decoder->complete()); EXPECT_THAT(response_decoder->headers(), IsSupersetOfHeaders(response_headers)); - EXPECT_EQ(response_decoder->headers().get(Http::Headers::get().Age), nullptr); + EXPECT_TRUE(response_decoder->headers().get(Http::Headers::get().Age).empty()); EXPECT_EQ(response_decoder->body(), response_body); EXPECT_THAT(waitForAccessLog(access_log_name_), testing::HasSubstr("- via_upstream")); } @@ -168,7 +168,7 @@ TEST_P(CacheIntegrationTest, ExpiredValidated) { // A response that has been validated should not contain an Age header as it is equivalent to a // freshly served response from the origin, unless the 304 response has an Age header, which // means it was served by an upstream cache. - EXPECT_EQ(response_decoder->headers().get(Http::Headers::get().Age), nullptr); + EXPECT_TRUE(response_decoder->headers().get(Http::Headers::get().Age).empty()); // Advance time to force a log flush. simTime().advanceTimeWait(Seconds(1)); @@ -210,7 +210,7 @@ TEST_P(CacheIntegrationTest, ExpiredFetchedNewResponse) { response_decoder->waitForEndStream(); EXPECT_TRUE(response_decoder->complete()); EXPECT_THAT(response_decoder->headers(), IsSupersetOfHeaders(response_headers)); - EXPECT_EQ(response_decoder->headers().get(Http::Headers::get().Age), nullptr); + EXPECT_TRUE(response_decoder->headers().get(Http::Headers::get().Age).empty()); EXPECT_EQ(response_decoder->body(), response_body); EXPECT_THAT(waitForAccessLog(access_log_name_), testing::HasSubstr("- via_upstream")); } @@ -249,7 +249,7 @@ TEST_P(CacheIntegrationTest, ExpiredFetchedNewResponse) { EXPECT_THAT(response_decoder->headers(), IsSupersetOfHeaders(response_headers)); EXPECT_EQ(response_decoder->body(), response_body); // Check that age header does not exist as this is not a cached response - EXPECT_EQ(response_decoder->headers().get(Http::Headers::get().Age), nullptr); + EXPECT_TRUE(response_decoder->headers().get(Http::Headers::get().Age).empty()); // Advance time to force a log flush. simTime().advanceTimeWait(Seconds(1)); @@ -291,7 +291,7 @@ TEST_P(CacheIntegrationTest, GetRequestWithBodyAndTrailers) { response->waitForEndStream(); EXPECT_TRUE(response->complete()); EXPECT_THAT(response->headers(), IsSupersetOfHeaders(response_headers)); - EXPECT_EQ(response->headers().get(Http::Headers::get().Age), nullptr); + EXPECT_TRUE(response->headers().get(Http::Headers::get().Age).empty()); EXPECT_EQ(response->body(), std::string(42, 'a')); } } diff --git a/test/extensions/filters/http/cache/cache_headers_utils_test.cc b/test/extensions/filters/http/cache/cache_headers_utils_test.cc index db6879799b81..0f29d63d6fe7 100644 --- a/test/extensions/filters/http/cache/cache_headers_utils_test.cc +++ b/test/extensions/filters/http/cache/cache_headers_utils_test.cc @@ -113,7 +113,7 @@ class RequestCacheControlTest : public testing::TestWithParam, // Empty header { - "", + "", // {must_validate_, no_store_, no_transform_, no_stale_, is_public_, max_age_} {false, false, false, false, false, absl::nullopt} }, @@ -211,7 +211,7 @@ class ResponseCacheControlTest : public testing::TestWithParamget(Http::LowerCaseString("accept"))); - EXPECT_FALSE(result->get(Http::LowerCaseString("accept-language"))); - EXPECT_FALSE(result->get(Http::LowerCaseString("width"))); + EXPECT_TRUE(result->get(Http::LowerCaseString("accept")).empty()); + EXPECT_TRUE(result->get(Http::LowerCaseString("accept-language")).empty()); + EXPECT_TRUE(result->get(Http::LowerCaseString("width")).empty()); } TEST_F(VaryHeaderTest, PossibleVariedHeadersNoOverlap) { request_headers_.addCopy("abc", "123"); Http::HeaderMapPtr result = vary_allow_list_.possibleVariedHeaders(request_headers_); - EXPECT_FALSE(result->get(Http::LowerCaseString("accept"))); - EXPECT_FALSE(result->get(Http::LowerCaseString("accept-language"))); - EXPECT_FALSE(result->get(Http::LowerCaseString("width"))); + EXPECT_TRUE(result->get(Http::LowerCaseString("accept")).empty()); + EXPECT_TRUE(result->get(Http::LowerCaseString("accept-language")).empty()); + EXPECT_TRUE(result->get(Http::LowerCaseString("width")).empty()); } TEST_F(VaryHeaderTest, PossibleVariedHeadersOverlap) { @@ -758,13 +758,12 @@ TEST_F(VaryHeaderTest, PossibleVariedHeadersOverlap) { request_headers_.addCopy("accept", "image/*"); Http::HeaderMapPtr result = vary_allow_list_.possibleVariedHeaders(request_headers_); - std::vector values; - Http::HeaderUtility::getAllOfHeader(*result, "accept", values); + const auto values = result->get(Http::LowerCaseString("accept")); ASSERT_EQ(values.size(), 1); - EXPECT_EQ(values[0], "image/*"); + EXPECT_EQ(values[0]->value().getStringView(), "image/*"); - EXPECT_FALSE(result->get(Http::LowerCaseString("accept-language"))); - EXPECT_FALSE(result->get(Http::LowerCaseString("width"))); + EXPECT_TRUE(result->get(Http::LowerCaseString("accept-language")).empty()); + EXPECT_TRUE(result->get(Http::LowerCaseString("width")).empty()); } TEST_F(VaryHeaderTest, PossibleVariedHeadersMultiValues) { @@ -772,14 +771,13 @@ TEST_F(VaryHeaderTest, PossibleVariedHeadersMultiValues) { request_headers_.addCopy("accept", "text/html"); Http::HeaderMapPtr result = vary_allow_list_.possibleVariedHeaders(request_headers_); - std::vector values; - Http::HeaderUtility::getAllOfHeader(*result, "accept", values); + const auto values = result->get(Http::LowerCaseString("accept")); ASSERT_EQ(values.size(), 2); - EXPECT_EQ(values[0], "image/*"); - EXPECT_EQ(values[1], "text/html"); + EXPECT_EQ(values[0]->value().getStringView(), "image/*"); + EXPECT_EQ(values[1]->value().getStringView(), "text/html"); - EXPECT_FALSE(result->get(Http::LowerCaseString("accept-language"))); - EXPECT_FALSE(result->get(Http::LowerCaseString("width"))); + EXPECT_TRUE(result->get(Http::LowerCaseString("accept-language")).empty()); + EXPECT_TRUE(result->get(Http::LowerCaseString("width")).empty()); } TEST_F(VaryHeaderTest, PossibleVariedHeadersMultiHeaders) { @@ -787,16 +785,15 @@ TEST_F(VaryHeaderTest, PossibleVariedHeadersMultiHeaders) { request_headers_.addCopy("accept-language", "en-US"); Http::HeaderMapPtr result = vary_allow_list_.possibleVariedHeaders(request_headers_); - std::vector values; - Http::HeaderUtility::getAllOfHeader(*result, "accept", values); + const auto values = result->get(Http::LowerCaseString("accept")); ASSERT_EQ(values.size(), 1); - EXPECT_EQ(values[0], "image/*"); + EXPECT_EQ(values[0]->value().getStringView(), "image/*"); - Http::HeaderUtility::getAllOfHeader(*result, "accept-language", values); - ASSERT_EQ(values.size(), 2); - EXPECT_EQ(values[1], "en-US"); + const auto values2 = result->get(Http::LowerCaseString("accept-language")); + ASSERT_EQ(values2.size(), 1); + EXPECT_EQ(values2[0]->value(), "en-US"); - EXPECT_FALSE(result->get(Http::LowerCaseString("width"))); + EXPECT_TRUE(result->get(Http::LowerCaseString("width")).empty()); } } // namespace diff --git a/test/extensions/filters/http/cache/http_cache_test.cc b/test/extensions/filters/http/cache/http_cache_test.cc index 122c46aec80d..0fd677973da1 100644 --- a/test/extensions/filters/http/cache/http_cache_test.cc +++ b/test/extensions/filters/http/cache/http_cache_test.cc @@ -635,9 +635,9 @@ TEST_F(LookupRequestTest, VariedHeaders) { const LookupRequest lookup_request(request_headers_, currentTime(), vary_allow_list_); const Http::RequestHeaderMap& result = lookup_request.getVaryHeaders(); - ASSERT_TRUE(result.get(Http::LowerCaseString("accept"))); - ASSERT_EQ(result.get(Http::LowerCaseString("accept"))->value().getStringView(), "image/*"); - ASSERT_FALSE(result.get(Http::LowerCaseString("other-header"))); + ASSERT_FALSE(result.get(Http::LowerCaseString("accept")).empty()); + ASSERT_EQ(result.get(Http::LowerCaseString("accept"))[0]->value().getStringView(), "image/*"); + ASSERT_TRUE(result.get(Http::LowerCaseString("other-header")).empty()); } } // namespace diff --git a/test/extensions/filters/http/cdn_loop/filter_integration_test.cc b/test/extensions/filters/http/cdn_loop/filter_integration_test.cc index 47861ef27a86..ed6032370dcf 100644 --- a/test/extensions/filters/http/cdn_loop/filter_integration_test.cc +++ b/test/extensions/filters/http/cdn_loop/filter_integration_test.cc @@ -40,9 +40,9 @@ TEST_P(CdnLoopFilterIntegrationTest, NoCdnLoopHeader) { auto response = sendRequestAndWaitForResponse(request_headers, 0, default_response_headers_, 0); - const auto* payload_entry = upstream_request_->headers().get(Http::LowerCaseString("CDN-Loop")); - ASSERT_NE(payload_entry, nullptr); - EXPECT_EQ(payload_entry->value().getStringView(), "cdn"); + const auto payload_entry = upstream_request_->headers().get(Http::LowerCaseString("CDN-Loop")); + ASSERT_FALSE(payload_entry.empty()); + EXPECT_EQ(payload_entry[0]->value().getStringView(), "cdn"); ASSERT_TRUE(response->complete()); EXPECT_EQ("200", response->headers().getStatusValue()); } @@ -60,9 +60,9 @@ TEST_P(CdnLoopFilterIntegrationTest, CdnLoopHeaderWithOtherCdns) { auto response = sendRequestAndWaitForResponse(request_headers, 0, default_response_headers_, 0); - const auto* payload_entry = upstream_request_->headers().get(Http::LowerCaseString("CDN-Loop")); - ASSERT_NE(payload_entry, nullptr); - EXPECT_EQ(payload_entry->value().getStringView(), "cdn1,cdn2,cdn"); + const auto payload_entry = upstream_request_->headers().get(Http::LowerCaseString("CDN-Loop")); + ASSERT_FALSE(payload_entry.empty()); + EXPECT_EQ(payload_entry[0]->value().getStringView(), "cdn1,cdn2,cdn"); ASSERT_TRUE(response->complete()); EXPECT_EQ("200", response->headers().getStatusValue()); } @@ -78,9 +78,9 @@ TEST_P(CdnLoopFilterIntegrationTest, MultipleCdnLoopHeaders) { auto response = sendRequestAndWaitForResponse(request_headers, 0, default_response_headers_, 0); - const auto* payload_entry = upstream_request_->headers().get(Http::LowerCaseString("CDN-Loop")); - ASSERT_NE(payload_entry, nullptr); - EXPECT_EQ(payload_entry->value().getStringView(), "cdn1,cdn2,cdn"); + const auto payload_entry = upstream_request_->headers().get(Http::LowerCaseString("CDN-Loop")); + ASSERT_FALSE(payload_entry.empty()); + EXPECT_EQ(payload_entry[0]->value().getStringView(), "cdn1,cdn2,cdn"); ASSERT_TRUE(response->complete()); EXPECT_EQ("200", response->headers().getStatusValue()); } @@ -132,9 +132,9 @@ TEST_P(CdnLoopFilterIntegrationTest, CdnLoop2Allowed1Seen) { auto response = sendRequestAndWaitForResponse(request_headers, 0, default_response_headers_, 0); - const auto* payload_entry = upstream_request_->headers().get(Http::LowerCaseString("CDN-Loop")); - ASSERT_NE(payload_entry, nullptr); - EXPECT_EQ(payload_entry->value().getStringView(), "cdn,cdn"); + const auto payload_entry = upstream_request_->headers().get(Http::LowerCaseString("CDN-Loop")); + ASSERT_FALSE(payload_entry.empty()); + EXPECT_EQ(payload_entry[0]->value().getStringView(), "cdn,cdn"); ASSERT_TRUE(response->complete()); EXPECT_EQ("200", response->headers().getStatusValue()); } @@ -152,9 +152,9 @@ TEST_P(CdnLoopFilterIntegrationTest, CdnLoop2Allowed2Seen) { auto response = sendRequestAndWaitForResponse(request_headers, 0, default_response_headers_, 0); - const auto* payload_entry = upstream_request_->headers().get(Http::LowerCaseString("CDN-Loop")); - ASSERT_NE(payload_entry, nullptr); - EXPECT_EQ(payload_entry->value().getStringView(), "cdn, cdn,cdn"); + const auto payload_entry = upstream_request_->headers().get(Http::LowerCaseString("CDN-Loop")); + ASSERT_FALSE(payload_entry.empty()); + EXPECT_EQ(payload_entry[0]->value().getStringView(), "cdn, cdn,cdn"); ASSERT_TRUE(response->complete()); EXPECT_EQ("200", response->headers().getStatusValue()); } diff --git a/test/extensions/filters/http/cdn_loop/filter_test.cc b/test/extensions/filters/http/cdn_loop/filter_test.cc index bd7e7d28cb01..9c96e26dca2d 100644 --- a/test/extensions/filters/http/cdn_loop/filter_test.cc +++ b/test/extensions/filters/http/cdn_loop/filter_test.cc @@ -23,7 +23,8 @@ TEST(CdnLoopFilterTest, TestNoHeader) { Http::TestRequestHeaderMapImpl request_headers{}; EXPECT_EQ(filter.decodeHeaders(request_headers, false), Http::FilterHeadersStatus::Continue); - EXPECT_EQ(request_headers.get(Http::LowerCaseString("CDN-Loop"))->value().getStringView(), "cdn"); + EXPECT_EQ(request_headers.get(Http::LowerCaseString("CDN-Loop"))[0]->value().getStringView(), + "cdn"); } TEST(CdnLoopFilterTest, OtherCdnsInHeader) { @@ -34,7 +35,7 @@ TEST(CdnLoopFilterTest, OtherCdnsInHeader) { Http::TestRequestHeaderMapImpl request_headers{{"CDN-Loop", "cdn1,cdn2"}}; EXPECT_EQ(filter.decodeHeaders(request_headers, false), Http::FilterHeadersStatus::Continue); - EXPECT_EQ(request_headers.get(Http::LowerCaseString("CDN-Loop"))->value().getStringView(), + EXPECT_EQ(request_headers.get(Http::LowerCaseString("CDN-Loop"))[0]->value().getStringView(), "cdn1,cdn2,cdn"); } @@ -58,25 +59,25 @@ TEST(CdnLoopFilterTest, MultipleTransitsAllowed) { { Http::TestRequestHeaderMapImpl request_headers{}; EXPECT_EQ(filter.decodeHeaders(request_headers, false), Http::FilterHeadersStatus::Continue); - EXPECT_EQ(request_headers.get(Http::LowerCaseString("CDN-Loop"))->value().getStringView(), + EXPECT_EQ(request_headers.get(Http::LowerCaseString("CDN-Loop"))[0]->value().getStringView(), "cdn"); } { Http::TestRequestHeaderMapImpl request_headers{{"CDN-Loop", "cdn"}}; EXPECT_EQ(filter.decodeHeaders(request_headers, false), Http::FilterHeadersStatus::Continue); - EXPECT_EQ(request_headers.get(Http::LowerCaseString("CDN-Loop"))->value().getStringView(), + EXPECT_EQ(request_headers.get(Http::LowerCaseString("CDN-Loop"))[0]->value().getStringView(), "cdn,cdn"); } { Http::TestRequestHeaderMapImpl request_headers{{"CDN-Loop", "cdn,cdn"}}; EXPECT_EQ(filter.decodeHeaders(request_headers, false), Http::FilterHeadersStatus::Continue); - EXPECT_EQ(request_headers.get(Http::LowerCaseString("CDN-Loop"))->value().getStringView(), + EXPECT_EQ(request_headers.get(Http::LowerCaseString("CDN-Loop"))[0]->value().getStringView(), "cdn,cdn,cdn"); } { Http::TestRequestHeaderMapImpl request_headers{{"CDN-Loop", "cdn,cdn,cdn"}}; EXPECT_EQ(filter.decodeHeaders(request_headers, false), Http::FilterHeadersStatus::Continue); - EXPECT_EQ(request_headers.get(Http::LowerCaseString("CDN-Loop"))->value().getStringView(), + EXPECT_EQ(request_headers.get(Http::LowerCaseString("CDN-Loop"))[0]->value().getStringView(), "cdn,cdn,cdn,cdn"); } { @@ -94,7 +95,7 @@ TEST(CdnLoopFilterTest, MultipleHeadersAllowed) { Http::TestRequestHeaderMapImpl request_headers{{"CDN-Loop", "cdn1"}, {"CDN-Loop", "cdn2"}}; EXPECT_EQ(filter.decodeHeaders(request_headers, false), Http::FilterHeadersStatus::Continue); - EXPECT_EQ(request_headers.get(Http::LowerCaseString("CDN-Loop"))->value().getStringView(), + EXPECT_EQ(request_headers.get(Http::LowerCaseString("CDN-Loop"))[0]->value().getStringView(), "cdn1,cdn2,cdn"); } diff --git a/test/extensions/filters/http/compressor/compressor_filter_integration_test.cc b/test/extensions/filters/http/compressor/compressor_filter_integration_test.cc index 0ded467631a2..623512513303 100644 --- a/test/extensions/filters/http/compressor/compressor_filter_integration_test.cc +++ b/test/extensions/filters/http/compressor/compressor_filter_integration_test.cc @@ -38,7 +38,7 @@ class CompressorIntegrationTest : public testing::TestWithParamheaders().getStatusValue()); EXPECT_EQ(Http::CustomHeaders::get().ContentEncodingValues.Gzip, response->headers() - .get(Http::CustomHeaders::get().ContentEncoding) + .get(Http::CustomHeaders::get().ContentEncoding)[0] ->value() .getStringView()); EXPECT_EQ(Http::Headers::get().TransferEncodingValues.Chunked, @@ -61,7 +61,7 @@ class CompressorIntegrationTest : public testing::TestWithParambodyLength()); EXPECT_TRUE(response->complete()); EXPECT_EQ("200", response->headers().getStatusValue()); - ASSERT_TRUE(response->headers().get(Http::CustomHeaders::get().ContentEncoding) == nullptr); + ASSERT_TRUE(response->headers().get(Http::CustomHeaders::get().ContentEncoding).empty()); ASSERT_EQ(content_length, response->body().size()); EXPECT_EQ(response->body(), std::string(content_length, 'a')); } @@ -188,9 +188,10 @@ TEST_P(CompressorIntegrationTest, UpstreamResponseAlreadyEncoded) { EXPECT_EQ(0U, upstream_request_->bodyLength()); EXPECT_TRUE(response->complete()); EXPECT_EQ("200", response->headers().getStatusValue()); - ASSERT_EQ( - "br", - response->headers().get(Http::CustomHeaders::get().ContentEncoding)->value().getStringView()); + ASSERT_EQ("br", response->headers() + .get(Http::CustomHeaders::get().ContentEncoding)[0] + ->value() + .getStringView()); EXPECT_EQ(128U, response->body().size()); } @@ -214,7 +215,7 @@ TEST_P(CompressorIntegrationTest, NotEnoughContentLength) { EXPECT_EQ(0U, upstream_request_->bodyLength()); EXPECT_TRUE(response->complete()); EXPECT_EQ("200", response->headers().getStatusValue()); - ASSERT_TRUE(response->headers().get(Http::CustomHeaders::get().ContentEncoding) == nullptr); + ASSERT_TRUE(response->headers().get(Http::CustomHeaders::get().ContentEncoding).empty()); EXPECT_EQ(10U, response->body().size()); } @@ -237,7 +238,7 @@ TEST_P(CompressorIntegrationTest, EmptyResponse) { EXPECT_EQ(0U, upstream_request_->bodyLength()); EXPECT_TRUE(response->complete()); EXPECT_EQ("204", response->headers().getStatusValue()); - ASSERT_TRUE(response->headers().get(Http::CustomHeaders::get().ContentEncoding) == nullptr); + ASSERT_TRUE(response->headers().get(Http::CustomHeaders::get().ContentEncoding).empty()); EXPECT_EQ(0U, response->body().size()); } @@ -292,9 +293,10 @@ TEST_P(CompressorIntegrationTest, AcceptanceFullConfigChunkedResponse) { EXPECT_EQ(0U, upstream_request_->bodyLength()); EXPECT_TRUE(response->complete()); EXPECT_EQ("200", response->headers().getStatusValue()); - ASSERT_EQ( - "gzip", - response->headers().get(Http::CustomHeaders::get().ContentEncoding)->value().getStringView()); + ASSERT_EQ("gzip", response->headers() + .get(Http::CustomHeaders::get().ContentEncoding)[0] + ->value() + .getStringView()); ASSERT_EQ("chunked", response->headers().getTransferEncodingValue()); } @@ -318,10 +320,11 @@ TEST_P(CompressorIntegrationTest, AcceptanceFullConfigVaryHeader) { EXPECT_EQ(0U, upstream_request_->bodyLength()); EXPECT_TRUE(response->complete()); EXPECT_EQ("200", response->headers().getStatusValue()); - ASSERT_EQ( - "gzip", - response->headers().get(Http::CustomHeaders::get().ContentEncoding)->value().getStringView()); + ASSERT_EQ("gzip", response->headers() + .get(Http::CustomHeaders::get().ContentEncoding)[0] + ->value() + .getStringView()); ASSERT_EQ("Cookie, Accept-Encoding", - response->headers().get(Http::CustomHeaders::get().Vary)->value().getStringView()); + response->headers().get(Http::CustomHeaders::get().Vary)[0]->value().getStringView()); } } // namespace Envoy diff --git a/test/extensions/filters/http/decompressor/decompressor_filter_integration_test.cc b/test/extensions/filters/http/decompressor/decompressor_filter_integration_test.cc index 1e1450f744ae..be709d1fcdb4 100644 --- a/test/extensions/filters/http/decompressor/decompressor_filter_integration_test.cc +++ b/test/extensions/filters/http/decompressor/decompressor_filter_integration_test.cc @@ -95,19 +95,19 @@ TEST_P(DecompressorIntegrationTest, BidirectionalDecompression) { // sent. EXPECT_TRUE(upstream_request_->complete()); EXPECT_EQ("gzip", upstream_request_->headers() - .get(Http::LowerCaseString("accept-encoding")) + .get(Http::LowerCaseString("accept-encoding"))[0] ->value() .getStringView()); - EXPECT_EQ(nullptr, upstream_request_->headers().get(Http::LowerCaseString("content-encoding"))); + EXPECT_TRUE(upstream_request_->headers().get(Http::LowerCaseString("content-encoding")).empty()); EXPECT_EQ(uncompressed_request_length, upstream_request_->bodyLength()); EXPECT_EQ(std::to_string(compressed_request_length), upstream_request_->trailers() - ->get(Http::LowerCaseString("x-envoy-decompressor-testlib-compressed-bytes")) + ->get(Http::LowerCaseString("x-envoy-decompressor-testlib-compressed-bytes"))[0] ->value() .getStringView()); EXPECT_EQ(std::to_string(uncompressed_request_length), upstream_request_->trailers() - ->get(Http::LowerCaseString("x-envoy-decompressor-testlib-uncompressed-bytes")) + ->get(Http::LowerCaseString("x-envoy-decompressor-testlib-uncompressed-bytes"))[0] ->value() .getStringView()); @@ -153,12 +153,12 @@ TEST_P(DecompressorIntegrationTest, BidirectionalDecompression) { EXPECT_EQ(uncompressed_response_length, response->body().length()); EXPECT_EQ(std::to_string(compressed_response_length), response->trailers() - ->get(Http::LowerCaseString("x-envoy-decompressor-testlib-compressed-bytes")) + ->get(Http::LowerCaseString("x-envoy-decompressor-testlib-compressed-bytes"))[0] ->value() .getStringView()); EXPECT_EQ(std::to_string(uncompressed_response_length), response->trailers() - ->get(Http::LowerCaseString("x-envoy-decompressor-testlib-uncompressed-bytes")) + ->get(Http::LowerCaseString("x-envoy-decompressor-testlib-uncompressed-bytes"))[0] ->value() .getStringView()); @@ -224,13 +224,13 @@ TEST_P(DecompressorIntegrationTest, BidirectionalDecompressionError) { EXPECT_TRUE(upstream_request_->complete()); EXPECT_EQ("gzip", upstream_request_->headers() - .get(Http::LowerCaseString("accept-encoding")) + .get(Http::LowerCaseString("accept-encoding"))[0] ->value() .getStringView()); - EXPECT_EQ(nullptr, upstream_request_->headers().get(Http::LowerCaseString("content-encoding"))); + EXPECT_TRUE(upstream_request_->headers().get(Http::LowerCaseString("content-encoding")).empty()); EXPECT_EQ(std::to_string(compressed_request_length), upstream_request_->trailers() - ->get(Http::LowerCaseString("x-envoy-decompressor-testlib-compressed-bytes")) + ->get(Http::LowerCaseString("x-envoy-decompressor-testlib-compressed-bytes"))[0] ->value() .getStringView()); @@ -270,7 +270,7 @@ TEST_P(DecompressorIntegrationTest, BidirectionalDecompressionError) { EXPECT_EQ("200", response->headers().Status()->value().getStringView()); EXPECT_EQ(std::to_string(compressed_response_length), response->trailers() - ->get(Http::LowerCaseString("x-envoy-decompressor-testlib-compressed-bytes")) + ->get(Http::LowerCaseString("x-envoy-decompressor-testlib-compressed-bytes"))[0] ->value() .getStringView()); diff --git a/test/extensions/filters/http/decompressor/decompressor_filter_test.cc b/test/extensions/filters/http/decompressor/decompressor_filter_test.cc index 5ae7accd1085..bd8f8891d3ec 100644 --- a/test/extensions/filters/http/decompressor/decompressor_filter_test.cc +++ b/test/extensions/filters/http/decompressor/decompressor_filter_test.cc @@ -78,14 +78,14 @@ class DecompressorFilterTest : public testing::TestWithParam { if (end_stream && expect_decompression) { EXPECT_EQ( "30", - trailers.get(Http::LowerCaseString("x-envoy-decompressor-testlib-compressed-bytes")) - ->value() - .getStringView()); - EXPECT_EQ( - "60", - trailers.get(Http::LowerCaseString("x-envoy-decompressor-testlib-uncompressed-bytes")) + trailers.get(Http::LowerCaseString("x-envoy-decompressor-testlib-compressed-bytes"))[0] ->value() .getStringView()); + EXPECT_EQ("60", trailers + .get(Http::LowerCaseString( + "x-envoy-decompressor-testlib-uncompressed-bytes"))[0] + ->value() + .getStringView()); } } else { Http::TestResponseTrailerMapImpl trailers; @@ -98,14 +98,14 @@ class DecompressorFilterTest : public testing::TestWithParam { if (end_stream && expect_decompression) { EXPECT_EQ( "30", - trailers.get(Http::LowerCaseString("x-envoy-decompressor-testlib-compressed-bytes")) - ->value() - .getStringView()); - EXPECT_EQ( - "60", - trailers.get(Http::LowerCaseString("x-envoy-decompressor-testlib-uncompressed-bytes")) + trailers.get(Http::LowerCaseString("x-envoy-decompressor-testlib-compressed-bytes"))[0] ->value() .getStringView()); + EXPECT_EQ("60", trailers + .get(Http::LowerCaseString( + "x-envoy-decompressor-testlib-uncompressed-bytes"))[0] + ->value() + .getStringView()); } } } @@ -116,27 +116,27 @@ class DecompressorFilterTest : public testing::TestWithParam { EXPECT_EQ(Http::FilterTrailersStatus::Continue, filter_->decodeTrailers(request_trailers)); EXPECT_EQ("30", request_trailers - .get(Http::LowerCaseString("x-envoy-decompressor-testlib-compressed-bytes")) - ->value() - .getStringView()); - EXPECT_EQ("60", - request_trailers - .get(Http::LowerCaseString("x-envoy-decompressor-testlib-uncompressed-bytes")) + .get(Http::LowerCaseString("x-envoy-decompressor-testlib-compressed-bytes"))[0] ->value() .getStringView()); + EXPECT_EQ("60", request_trailers + .get(Http::LowerCaseString( + "x-envoy-decompressor-testlib-uncompressed-bytes"))[0] + ->value() + .getStringView()); } else { Http::TestResponseTrailerMapImpl response_trailers; EXPECT_EQ(Http::FilterTrailersStatus::Continue, filter_->encodeTrailers(response_trailers)); EXPECT_EQ("30", response_trailers - .get(Http::LowerCaseString("x-envoy-decompressor-testlib-compressed-bytes")) - ->value() - .getStringView()); - EXPECT_EQ("60", - response_trailers - .get(Http::LowerCaseString("x-envoy-decompressor-testlib-uncompressed-bytes")) + .get(Http::LowerCaseString("x-envoy-decompressor-testlib-compressed-bytes"))[0] ->value() .getStringView()); + EXPECT_EQ("60", response_trailers + .get(Http::LowerCaseString( + "x-envoy-decompressor-testlib-uncompressed-bytes"))[0] + ->value() + .getStringView()); } } @@ -186,21 +186,21 @@ class DecompressorFilterTest : public testing::TestWithParam { // The filter removes the decompressor's content encoding from the Content-Encoding header. if (expected_content_encoding.has_value()) { EXPECT_EQ(expected_content_encoding.value(), - headers_after_filter->get(Http::CustomHeaders::get().ContentEncoding) + headers_after_filter->get(Http::CustomHeaders::get().ContentEncoding)[0] ->value() .getStringView()); } else { - EXPECT_EQ(nullptr, headers_after_filter->get(Http::CustomHeaders::get().ContentEncoding)); + EXPECT_TRUE(headers_after_filter->get(Http::CustomHeaders::get().ContentEncoding).empty()); } // The filter adds the decompressor's content encoding to the Accept-Encoding header on the // request direction. - const auto* accept_encoding = + const auto accept_encoding = headers_after_filter->get(Http::LowerCaseString{"accept-encoding"}); if (isRequestDirection() && expected_accept_encoding.has_value()) { - EXPECT_EQ(expected_accept_encoding.value(), accept_encoding->value().getStringView()); + EXPECT_EQ(expected_accept_encoding.value(), accept_encoding[0]->value().getStringView()); } else { - EXPECT_EQ(nullptr, accept_encoding); + EXPECT_TRUE(accept_encoding.empty()); } expectDecompression(decompressor_ptr, end_with_data); @@ -399,7 +399,7 @@ TEST_P(DecompressorFilterTest, NoDecompressionHeadersOnly) { doHeaders(headers_before_filter, true /* end_stream */); if (isRequestDirection()) { - ASSERT_EQ(headers_after_filter->get(Http::LowerCaseString("accept-encoding")) + ASSERT_EQ(headers_after_filter->get(Http::LowerCaseString("accept-encoding"))[0] ->value() .getStringView(), "mock"); @@ -418,7 +418,7 @@ TEST_P(DecompressorFilterTest, NoDecompressionContentEncodingAbsent) { doHeaders(headers_before_filter, false /* end_stream */); if (isRequestDirection()) { - ASSERT_EQ(headers_after_filter->get(Http::LowerCaseString("accept-encoding")) + ASSERT_EQ(headers_after_filter->get(Http::LowerCaseString("accept-encoding"))[0] ->value() .getStringView(), "mock"); @@ -451,7 +451,7 @@ TEST_P(DecompressorFilterTest, NoDecompressionContentEncodingNotCurrent) { doHeaders(headers_before_filter, false /* end_stream */); if (isRequestDirection()) { - ASSERT_EQ(headers_after_filter->get(Http::LowerCaseString("accept-encoding")) + ASSERT_EQ(headers_after_filter->get(Http::LowerCaseString("accept-encoding"))[0] ->value() .getStringView(), "mock"); @@ -474,7 +474,7 @@ TEST_P(DecompressorFilterTest, NoResponseDecompressionNoTransformPresent) { doHeaders(headers_before_filter, false /* end_stream */); if (isRequestDirection()) { - ASSERT_EQ(headers_after_filter->get(Http::LowerCaseString("accept-encoding")) + ASSERT_EQ(headers_after_filter->get(Http::LowerCaseString("accept-encoding"))[0] ->value() .getStringView(), "mock"); @@ -498,7 +498,7 @@ TEST_P(DecompressorFilterTest, NoResponseDecompressionNoTransformPresentInList) doHeaders(headers_before_filter, false /* end_stream */); if (isRequestDirection()) { - ASSERT_EQ(headers_after_filter->get(Http::LowerCaseString("accept-encoding")) + ASSERT_EQ(headers_after_filter->get(Http::LowerCaseString("accept-encoding"))[0] ->value() .getStringView(), "mock"); diff --git a/test/extensions/filters/http/ext_authz/ext_authz_integration_test.cc b/test/extensions/filters/http/ext_authz/ext_authz_integration_test.cc index 85401bef4684..0d48ac15cfb7 100644 --- a/test/extensions/filters/http/ext_authz/ext_authz_integration_test.cc +++ b/test/extensions/filters/http/ext_authz/ext_authz_integration_test.cc @@ -204,7 +204,7 @@ class ExtAuthzGrpcIntegrationTest : public Grpc::VersionedGrpcClientIntegrationP // string value. Hence for "header2" key, the value is "header2,header2-appended". absl::StrCat(header_to_append.first, ",", header_to_append.second))); const auto value = upstream_request_->headers() - .get(Http::LowerCaseString(header_to_append.first)) + .get(Http::LowerCaseString(header_to_append.first))[0] ->value() .getStringView(); EXPECT_TRUE(absl::EndsWith(value, "-appended")); @@ -230,8 +230,8 @@ class ExtAuthzGrpcIntegrationTest : public Grpc::VersionedGrpcClientIntegrationP for (const auto& header_to_remove : headers_to_remove) { // The headers that were originally present in the request have now been removed. - EXPECT_EQ(upstream_request_->headers().get(Http::LowerCaseString{header_to_remove.first}), - nullptr); + EXPECT_TRUE( + upstream_request_->headers().get(Http::LowerCaseString{header_to_remove.first}).empty()); } response_->waitForEndStream(); @@ -548,13 +548,13 @@ class ExtAuthzHttpIntegrationTest : public HttpIntegrationTest, // The "remove-me" header that was present in the downstream request has // been removed by envoy as a result of being present in // "x-envoy-auth-headers-to-remove". - EXPECT_EQ(upstream_request_->headers().get(Http::LowerCaseString{"remove-me"}), nullptr); + EXPECT_TRUE(upstream_request_->headers().get(Http::LowerCaseString{"remove-me"}).empty()); // "x-envoy-auth-headers-to-remove" itself has also been removed because // it's only used for communication between the authorization server and // envoy itself. - EXPECT_EQ( - upstream_request_->headers().get(Http::LowerCaseString{"x-envoy-auth-headers-to-remove"}), - nullptr); + EXPECT_TRUE(upstream_request_->headers() + .get(Http::LowerCaseString{"x-envoy-auth-headers-to-remove"}) + .empty()); upstream_request_->encodeHeaders(Http::TestResponseHeaderMapImpl{{":status", "200"}}, true); response_->waitForEndStream(); @@ -688,8 +688,8 @@ INSTANTIATE_TEST_SUITE_P(IpVersions, ExtAuthzHttpIntegrationTest, // Verifies that by default HTTP service uses the case-sensitive string matcher. TEST_P(ExtAuthzHttpIntegrationTest, DefaultCaseSensitiveStringMatcher) { setup(); - const auto* header_entry = ext_authz_request_->headers().get(case_sensitive_header_name_); - ASSERT_EQ(header_entry, nullptr); + const auto header_entry = ext_authz_request_->headers().get(case_sensitive_header_name_); + ASSERT_TRUE(header_entry.empty()); } TEST_P(ExtAuthzHttpIntegrationTest, CheckTimesOutLegacy) { expectCheckRequestTimedout(false); } diff --git a/test/extensions/filters/http/ext_authz/ext_authz_test.cc b/test/extensions/filters/http/ext_authz/ext_authz_test.cc index fdedea7546f1..456f62328c92 100644 --- a/test/extensions/filters/http/ext_authz/ext_authz_test.cc +++ b/test/extensions/filters/http/ext_authz/ext_authz_test.cc @@ -759,7 +759,7 @@ TEST_F(HttpFilterTest, HeadersToRemoveRemovesHeadersExceptSpecialHeaders) { EXPECT_EQ("/users", request_headers_.get_(Http::Headers::get().Path)); EXPECT_EQ("websocket", request_headers_.get_(Http::Headers::get().Protocol)); EXPECT_EQ("https", request_headers_.get_(Http::Headers::get().Scheme)); - EXPECT_EQ(nullptr, request_headers_.get(Http::LowerCaseString{"remove-me"})); + EXPECT_TRUE(request_headers_.get(Http::LowerCaseString{"remove-me"}).empty()); } // Verifies that the filter clears the route cache when an authorization response: @@ -1879,10 +1879,11 @@ TEST_P(HttpFilterTestParam, OverrideEncodingHeaders) { EXPECT_EQ(test_headers.get_("foobar"), "DO_NOT_OVERRIDE"); EXPECT_EQ(test_headers.get_("accept-encoding"), "gzip,deflate"); EXPECT_EQ(data.toString(), "foo"); - - std::vector setCookieHeaderValues; - Http::HeaderUtility::getAllOfHeader(test_headers, "set-cookie", setCookieHeaderValues); - EXPECT_THAT(setCookieHeaderValues, UnorderedElementsAre("cookie1=value", "cookie2=value")); + EXPECT_EQ(Http::HeaderUtility::getAllOfHeaderAsString(test_headers, + Http::LowerCaseString("set-cookie")) + .result() + .value(), + "cookie1=value,cookie2=value"); })); request_callbacks_->onComplete(std::move(response_ptr)); diff --git a/test/extensions/filters/http/grpc_json_transcoder/grpc_json_transcoder_integration_test.cc b/test/extensions/filters/http/grpc_json_transcoder/grpc_json_transcoder_integration_test.cc index 70ed3edf2768..473d9bfa655f 100644 --- a/test/extensions/filters/http/grpc_json_transcoder/grpc_json_transcoder_integration_test.cc +++ b/test/extensions/filters/http/grpc_json_transcoder/grpc_json_transcoder_integration_test.cc @@ -120,23 +120,23 @@ class GrpcJsonTranscoderIntegrationTest response->waitForEndStream(); EXPECT_TRUE(response->complete()); - if (response->headers().get(Http::LowerCaseString("transfer-encoding")) == nullptr || + if (response->headers().get(Http::LowerCaseString("transfer-encoding")).empty() || !absl::StartsWith(response->headers() - .get(Http::LowerCaseString("transfer-encoding")) + .get(Http::LowerCaseString("transfer-encoding"))[0] ->value() .getStringView(), "chunked")) { - EXPECT_EQ(response->headers().get(Http::LowerCaseString("trailer")), nullptr); + EXPECT_TRUE(response->headers().get(Http::LowerCaseString("trailer")).empty()); } response_headers.iterate( [response = response.get()](const Http::HeaderEntry& entry) -> Http::HeaderMap::Iterate { Http::LowerCaseString lower_key{std::string(entry.key().getStringView())}; if (entry.value() == UnexpectedHeaderValue) { - EXPECT_FALSE(response->headers().get(lower_key)); + EXPECT_TRUE(response->headers().get(lower_key).empty()); } else { EXPECT_EQ(entry.value().getStringView(), - response->headers().get(lower_key)->value().getStringView()); + response->headers().get(lower_key)[0]->value().getStringView()); } return Http::HeaderMap::Iterate::Continue; }); @@ -427,7 +427,7 @@ TEST_P(GrpcJsonTranscoderIntegrationTest, StreamGetHttpBodyFragmented) { EXPECT_EQ(response->body(), http_body.data()); // As well as content-type header auto content_type = response->headers().get(Http::LowerCaseString("content-type")); - EXPECT_EQ("text/plain", content_type->value().getStringView()); + EXPECT_EQ("text/plain", content_type[0]->value().getStringView()); } TEST_P(GrpcJsonTranscoderIntegrationTest, UnaryEchoHttpBody) { diff --git a/test/extensions/filters/http/gzip/gzip_filter_integration_test.cc b/test/extensions/filters/http/gzip/gzip_filter_integration_test.cc index 8996e2aa0684..50ad7f30422a 100644 --- a/test/extensions/filters/http/gzip/gzip_filter_integration_test.cc +++ b/test/extensions/filters/http/gzip/gzip_filter_integration_test.cc @@ -36,10 +36,10 @@ class GzipIntegrationTest : public testing::TestWithParambodyLength()); EXPECT_TRUE(response->complete()); EXPECT_EQ("200", response->headers().getStatusValue()); - ASSERT_TRUE(response->headers().get(Http::CustomHeaders::get().ContentEncoding) != nullptr); + ASSERT_FALSE(response->headers().get(Http::CustomHeaders::get().ContentEncoding).empty()); EXPECT_EQ(Http::CustomHeaders::get().ContentEncodingValues.Gzip, response->headers() - .get(Http::CustomHeaders::get().ContentEncoding) + .get(Http::CustomHeaders::get().ContentEncoding)[0] ->value() .getStringView()); ASSERT_TRUE(response->headers().TransferEncoding() != nullptr); @@ -63,7 +63,7 @@ class GzipIntegrationTest : public testing::TestWithParambodyLength()); EXPECT_TRUE(response->complete()); EXPECT_EQ("200", response->headers().getStatusValue()); - ASSERT_TRUE(response->headers().get(Http::CustomHeaders::get().ContentEncoding) == nullptr); + ASSERT_TRUE(response->headers().get(Http::CustomHeaders::get().ContentEncoding).empty()); ASSERT_EQ(content_length, response->body().size()); EXPECT_EQ(response->body(), std::string(content_length, 'a')); } @@ -209,9 +209,10 @@ TEST_P(GzipIntegrationTest, DEPRECATED_FEATURE_TEST(UpstreamResponseAlreadyEncod EXPECT_EQ(0U, upstream_request_->bodyLength()); EXPECT_TRUE(response->complete()); EXPECT_EQ("200", response->headers().getStatusValue()); - ASSERT_EQ( - "br", - response->headers().get(Http::CustomHeaders::get().ContentEncoding)->value().getStringView()); + ASSERT_EQ("br", response->headers() + .get(Http::CustomHeaders::get().ContentEncoding)[0] + ->value() + .getStringView()); EXPECT_EQ(128U, response->body().size()); } @@ -235,7 +236,7 @@ TEST_P(GzipIntegrationTest, DEPRECATED_FEATURE_TEST(NotEnoughContentLength)) { EXPECT_EQ(0U, upstream_request_->bodyLength()); EXPECT_TRUE(response->complete()); EXPECT_EQ("200", response->headers().getStatusValue()); - ASSERT_TRUE(response->headers().get(Http::CustomHeaders::get().ContentEncoding) == nullptr); + ASSERT_TRUE(response->headers().get(Http::CustomHeaders::get().ContentEncoding).empty()); EXPECT_EQ(10U, response->body().size()); } @@ -258,7 +259,7 @@ TEST_P(GzipIntegrationTest, DEPRECATED_FEATURE_TEST(EmptyResponse)) { EXPECT_EQ(0U, upstream_request_->bodyLength()); EXPECT_TRUE(response->complete()); EXPECT_EQ("204", response->headers().getStatusValue()); - ASSERT_TRUE(response->headers().get(Http::CustomHeaders::get().ContentEncoding) == nullptr); + ASSERT_TRUE(response->headers().get(Http::CustomHeaders::get().ContentEncoding).empty()); EXPECT_EQ(0U, response->body().size()); } @@ -313,9 +314,10 @@ TEST_P(GzipIntegrationTest, DEPRECATED_FEATURE_TEST(AcceptanceFullConfigChunkedR EXPECT_EQ(0U, upstream_request_->bodyLength()); EXPECT_TRUE(response->complete()); EXPECT_EQ("200", response->headers().getStatusValue()); - ASSERT_EQ( - "gzip", - response->headers().get(Http::CustomHeaders::get().ContentEncoding)->value().getStringView()); + ASSERT_EQ("gzip", response->headers() + .get(Http::CustomHeaders::get().ContentEncoding)[0] + ->value() + .getStringView()); ASSERT_EQ("chunked", response->headers().getTransferEncodingValue()); } @@ -339,10 +341,11 @@ TEST_P(GzipIntegrationTest, DEPRECATED_FEATURE_TEST(AcceptanceFullConfigVaryHead EXPECT_EQ(0U, upstream_request_->bodyLength()); EXPECT_TRUE(response->complete()); EXPECT_EQ("200", response->headers().getStatusValue()); - ASSERT_EQ( - "gzip", - response->headers().get(Http::CustomHeaders::get().ContentEncoding)->value().getStringView()); + ASSERT_EQ("gzip", response->headers() + .get(Http::CustomHeaders::get().ContentEncoding)[0] + ->value() + .getStringView()); ASSERT_EQ("Cookie, Accept-Encoding", - response->headers().get(Http::CustomHeaders::get().Vary)->value().getStringView()); + response->headers().get(Http::CustomHeaders::get().Vary)[0]->value().getStringView()); } } // namespace Envoy diff --git a/test/extensions/filters/http/jwt_authn/extractor_test.cc b/test/extensions/filters/http/jwt_authn/extractor_test.cc index a32d819fbeae..07fce913059f 100644 --- a/test/extensions/filters/http/jwt_authn/extractor_test.cc +++ b/test/extensions/filters/http/jwt_authn/extractor_test.cc @@ -167,7 +167,7 @@ TEST_F(ExtractorTest, TestCustomHeaderToken) { // Test token remove tokens[0]->removeJwt(headers); - EXPECT_FALSE(headers.get(Http::LowerCaseString("token-header"))); + EXPECT_FALSE(headers.has(Http::LowerCaseString("token-header"))); } // Make sure a double custom header concatenates the token @@ -203,7 +203,7 @@ TEST_F(ExtractorTest, TestPrefixHeaderMatch) { // Test token remove tokens[0]->removeJwt(headers); - EXPECT_FALSE(headers.get(Http::LowerCaseString("prefix-header"))); + EXPECT_FALSE(headers.has(Http::LowerCaseString("prefix-header"))); } // Test extracting token from the custom header: "prefix-header" diff --git a/test/extensions/filters/http/jwt_authn/filter_integration_test.cc b/test/extensions/filters/http/jwt_authn/filter_integration_test.cc index 4c3dc3a36cf4..4c71a7bef275 100644 --- a/test/extensions/filters/http/jwt_authn/filter_integration_test.cc +++ b/test/extensions/filters/http/jwt_authn/filter_integration_test.cc @@ -31,10 +31,10 @@ class HeaderToFilterStateFilter : public Http::PassThroughDecoderFilter { : header_(header), state_(state) {} Http::FilterHeadersStatus decodeHeaders(Http::RequestHeaderMap& headers, bool) override { - const Http::HeaderEntry* entry = headers.get(header_); - if (entry) { + const auto entry = headers.get(header_); + if (!entry.empty()) { decoder_callbacks_->streamInfo().filterState()->setData( - state_, std::make_unique(entry->value().getStringView()), + state_, std::make_unique(entry[0]->value().getStringView()), StreamInfo::FilterState::StateType::ReadOnly, StreamInfo::FilterState::LifeSpan::FilterChain); } @@ -109,12 +109,12 @@ TEST_P(LocalJwksIntegrationTest, WithGoodToken) { }); waitForNextUpstreamRequest(); - const auto* payload_entry = + const auto payload_entry = upstream_request_->headers().get(Http::LowerCaseString("sec-istio-auth-userinfo")); - EXPECT_TRUE(payload_entry != nullptr); - EXPECT_EQ(payload_entry->value().getStringView(), ExpectedPayloadValue); + EXPECT_FALSE(payload_entry.empty()); + EXPECT_EQ(payload_entry[0]->value().getStringView(), ExpectedPayloadValue); // Verify the token is removed. - EXPECT_EQ(nullptr, upstream_request_->headers().get(Http::CustomHeaders::get().Authorization)); + EXPECT_TRUE(upstream_request_->headers().get(Http::CustomHeaders::get().Authorization).empty()); upstream_request_->encodeHeaders(Http::TestResponseHeaderMapImpl{{":status", "200"}}, true); response->waitForEndStream(); ASSERT_TRUE(response->complete()); @@ -386,12 +386,12 @@ TEST_P(RemoteJwksIntegrationTest, WithGoodToken) { waitForNextUpstreamRequest(); - const auto* payload_entry = + const auto payload_entry = upstream_request_->headers().get(Http::LowerCaseString("sec-istio-auth-userinfo")); - EXPECT_TRUE(payload_entry != nullptr); - EXPECT_EQ(payload_entry->value().getStringView(), ExpectedPayloadValue); + EXPECT_FALSE(payload_entry.empty()); + EXPECT_EQ(payload_entry[0]->value().getStringView(), ExpectedPayloadValue); // Verify the token is removed. - EXPECT_EQ(nullptr, upstream_request_->headers().get(Http::CustomHeaders::get().Authorization)); + EXPECT_TRUE(upstream_request_->headers().get(Http::CustomHeaders::get().Authorization).empty()); upstream_request_->encodeHeaders(Http::TestResponseHeaderMapImpl{{":status", "200"}}, true); diff --git a/test/extensions/filters/http/local_ratelimit/filter_test.cc b/test/extensions/filters/http/local_ratelimit/filter_test.cc index e3d3cd538ff4..9662f9a783e1 100644 --- a/test/extensions/filters/http/local_ratelimit/filter_test.cc +++ b/test/extensions/filters/http/local_ratelimit/filter_test.cc @@ -113,7 +113,7 @@ TEST_F(FilterTest, RequestRateLimited) { Http::TestResponseHeaderMapImpl response_headers{{":status", "200"}}; modify_headers(response_headers); - EXPECT_EQ("true", response_headers.get(Http::LowerCaseString("x-test-rate-limit")) + EXPECT_EQ("true", response_headers.get(Http::LowerCaseString("x-test-rate-limit"))[0] ->value() .getStringView()); diff --git a/test/extensions/filters/http/lua/lua_filter_test.cc b/test/extensions/filters/http/lua/lua_filter_test.cc index ac4ab9514037..b5b20846a119 100644 --- a/test/extensions/filters/http/lua/lua_filter_test.cc +++ b/test/extensions/filters/http/lua/lua_filter_test.cc @@ -2140,7 +2140,7 @@ TEST_F(LuaHttpFilterTest, LuaFilterDisabled) { Http::TestRequestHeaderMapImpl request_headers_2{{":path", "/"}}; EXPECT_EQ(Http::FilterHeadersStatus::Continue, filter_->decodeHeaders(request_headers_2, true)); - EXPECT_EQ(nullptr, request_headers_2.get(Http::LowerCaseString("hello"))); + EXPECT_FALSE(request_headers_2.has("hello")); } // Test whether the route can directly reuse the Lua code in the global configuration. @@ -2204,7 +2204,7 @@ TEST_F(LuaHttpFilterTest, LuaFilterRefSourceCodeNotExist) { Http::TestRequestHeaderMapImpl request_headers{{":path", "/"}}; EXPECT_EQ(Http::FilterHeadersStatus::Continue, filter_->decodeHeaders(request_headers, true)); - EXPECT_EQ(nullptr, request_headers.get(Http::LowerCaseString("hello"))); + EXPECT_TRUE(request_headers.get(Http::LowerCaseString("hello")).empty()); } TEST_F(LuaHttpFilterTest, LuaFilterBase64Escape) { diff --git a/test/extensions/filters/http/lua/lua_integration_test.cc b/test/extensions/filters/http/lua/lua_integration_test.cc index b5c9c1f38256..7c99faea6df1 100644 --- a/test/extensions/filters/http/lua/lua_integration_test.cc +++ b/test/extensions/filters/http/lua/lua_integration_test.cc @@ -169,9 +169,10 @@ class LuaIntegrationTest : public testing::TestWithParamwaitForEndStream(); - EXPECT_EQ( - "2", - response->headers().get(Http::LowerCaseString("content-length"))->value().getStringView()); + EXPECT_EQ("2", response->headers() + .get(Http::LowerCaseString("content-length"))[0] + ->value() + .getStringView()); EXPECT_EQ("ok", response->body()); cleanup(); } @@ -296,31 +297,31 @@ name: lua waitForNextUpstreamRequest(); EXPECT_EQ("10", upstream_request_->headers() - .get(Http::LowerCaseString("request_body_size")) + .get(Http::LowerCaseString("request_body_size"))[0] ->value() .getStringView()); EXPECT_EQ("bar", upstream_request_->headers() - .get(Http::LowerCaseString("request_metadata_foo")) + .get(Http::LowerCaseString("request_metadata_foo"))[0] ->value() .getStringView()); EXPECT_EQ("bat", upstream_request_->headers() - .get(Http::LowerCaseString("request_metadata_baz")) + .get(Http::LowerCaseString("request_metadata_baz"))[0] ->value() .getStringView()); EXPECT_EQ("false", upstream_request_->headers() - .get(Http::LowerCaseString("request_secure")) + .get(Http::LowerCaseString("request_secure"))[0] ->value() .getStringView()); EXPECT_EQ("HTTP/1.1", upstream_request_->headers() - .get(Http::LowerCaseString("request_protocol")) + .get(Http::LowerCaseString("request_protocol"))[0] ->value() .getStringView()); EXPECT_EQ("bar", upstream_request_->headers() - .get(Http::LowerCaseString("request_dynamic_metadata_value")) + .get(Http::LowerCaseString("request_dynamic_metadata_value"))[0] ->value() .getStringView()); @@ -334,21 +335,22 @@ name: lua response->waitForEndStream(); EXPECT_EQ("7", response->headers() - .get(Http::LowerCaseString("response_body_size")) + .get(Http::LowerCaseString("response_body_size"))[0] ->value() .getStringView()); EXPECT_EQ("bar", response->headers() - .get(Http::LowerCaseString("response_metadata_foo")) + .get(Http::LowerCaseString("response_metadata_foo"))[0] ->value() .getStringView()); EXPECT_EQ("bat", response->headers() - .get(Http::LowerCaseString("response_metadata_baz")) + .get(Http::LowerCaseString("response_metadata_baz"))[0] ->value() .getStringView()); - EXPECT_EQ( - "HTTP/1.1", - response->headers().get(Http::LowerCaseString("request_protocol"))->value().getStringView()); - EXPECT_EQ(nullptr, response->headers().get(Http::LowerCaseString("foo"))); + EXPECT_EQ("HTTP/1.1", response->headers() + .get(Http::LowerCaseString("request_protocol"))[0] + ->value() + .getStringView()); + EXPECT_TRUE(response->headers().get(Http::LowerCaseString("foo")).empty()); cleanup(); } @@ -397,11 +399,11 @@ name: lua waitForNextUpstreamRequest(); EXPECT_EQ("bar", upstream_request_->headers() - .get(Http::LowerCaseString("upstream_foo")) + .get(Http::LowerCaseString("upstream_foo"))[0] ->value() .getStringView()); EXPECT_EQ("4", upstream_request_->headers() - .get(Http::LowerCaseString("upstream_body_size")) + .get(Http::LowerCaseString("upstream_body_size"))[0] ->value() .getStringView()); @@ -662,12 +664,12 @@ name: lua waitForNextUpstreamRequest(); EXPECT_EQ("approved", upstream_request_->headers() - .get(Http::LowerCaseString("signature_verification")) + .get(Http::LowerCaseString("signature_verification"))[0] ->value() .getStringView()); EXPECT_EQ("done", upstream_request_->headers() - .get(Http::LowerCaseString("verification")) + .get(Http::LowerCaseString("verification"))[0] ->value() .getStringView()); @@ -804,11 +806,11 @@ TEST_P(LuaIntegrationTest, BasicTestOfLuaPerRoute) { auto response = codec_client_->makeHeaderOnlyRequest(request_headers); waitForNextUpstreamRequest(1); - auto* entry = upstream_request_->headers().get(Http::LowerCaseString("code")); + auto entry = upstream_request_->headers().get(Http::LowerCaseString("code")); if (!expected_value.empty()) { - EXPECT_EQ(expected_value, entry->value().getStringView()); + EXPECT_EQ(expected_value, entry[0]->value().getStringView()); } else { - EXPECT_EQ(nullptr, entry); + EXPECT_TRUE(entry.empty()); } upstream_request_->encodeHeaders(default_response_headers_, true); @@ -888,11 +890,11 @@ TEST_P(LuaIntegrationTest, RdsTestOfLuaPerRoute) { auto response = codec_client_->makeHeaderOnlyRequest(request_headers); waitForNextUpstreamRequest(1); - auto* entry = upstream_request_->headers().get(Http::LowerCaseString("code")); + auto entry = upstream_request_->headers().get(Http::LowerCaseString("code")); if (!expected_value.empty()) { - EXPECT_EQ(expected_value, entry->value().getStringView()); + EXPECT_EQ(expected_value, entry[0]->value().getStringView()); } else { - EXPECT_EQ(nullptr, entry); + EXPECT_TRUE(entry.empty()); } upstream_request_->encodeHeaders(default_response_headers_, true); diff --git a/test/extensions/filters/http/ratelimit/ratelimit_integration_test.cc b/test/extensions/filters/http/ratelimit/ratelimit_integration_test.cc index d0c6eb0b4809..56114f530aca 100644 --- a/test/extensions/filters/http/ratelimit/ratelimit_integration_test.cc +++ b/test/extensions/filters/http/ratelimit/ratelimit_integration_test.cc @@ -237,14 +237,14 @@ TEST_P(RatelimitIntegrationTest, OkWithHeaders) { ratelimit_response_headers.iterate( [response = response_.get()](const Http::HeaderEntry& entry) -> Http::HeaderMap::Iterate { Http::LowerCaseString lower_key{std::string(entry.key().getStringView())}; - EXPECT_EQ(entry.value(), response->headers().get(lower_key)->value().getStringView()); + EXPECT_EQ(entry.value(), response->headers().get(lower_key)[0]->value().getStringView()); return Http::HeaderMap::Iterate::Continue; }); request_headers_to_add.iterate([upstream = upstream_request_.get()]( const Http::HeaderEntry& entry) -> Http::HeaderMap::Iterate { Http::LowerCaseString lower_key{std::string(entry.key().getStringView())}; - EXPECT_EQ(entry.value(), upstream->headers().get(lower_key)->value().getStringView()); + EXPECT_EQ(entry.value(), upstream->headers().get(lower_key)[0]->value().getStringView()); return Http::HeaderMap::Iterate::Continue; }); @@ -280,7 +280,7 @@ TEST_P(RatelimitIntegrationTest, OverLimitWithHeaders) { ratelimit_response_headers.iterate( [response = response_.get()](const Http::HeaderEntry& entry) -> Http::HeaderMap::Iterate { Http::LowerCaseString lower_key{std::string(entry.key().getStringView())}; - EXPECT_EQ(entry.value(), response->headers().get(lower_key)->value().getStringView()); + EXPECT_EQ(entry.value(), response->headers().get(lower_key)[0]->value().getStringView()); return Http::HeaderMap::Iterate::Continue; }); diff --git a/test/extensions/filters/network/thrift_proxy/conn_manager_test.cc b/test/extensions/filters/network/thrift_proxy/conn_manager_test.cc index 47a49f9bad32..9798db6e2e9c 100644 --- a/test/extensions/filters/network/thrift_proxy/conn_manager_test.cc +++ b/test/extensions/filters/network/thrift_proxy/conn_manager_test.cc @@ -1366,9 +1366,9 @@ TEST_F(ThriftConnectionManagerTest, DecoderFiltersModifyRequests) { })); EXPECT_CALL(*decoder_filter_, transportBegin(_)) .WillOnce(Invoke([&](MessageMetadataSharedPtr metadata) -> FilterStatus { - const Http::HeaderEntry* header = metadata->headers().get(key); - EXPECT_NE(nullptr, header); - EXPECT_EQ("value", header->value().getStringView()); + const auto header = metadata->headers().get(key); + EXPECT_FALSE(header.empty()); + EXPECT_EQ("value", header[0]->value().getStringView()); return FilterStatus::Continue; })); diff --git a/test/extensions/quic_listeners/quiche/envoy_quic_client_stream_test.cc b/test/extensions/quic_listeners/quiche/envoy_quic_client_stream_test.cc index 98359c618b0f..ac82239db0bb 100644 --- a/test/extensions/quic_listeners/quiche/envoy_quic_client_stream_test.cc +++ b/test/extensions/quic_listeners/quiche/envoy_quic_client_stream_test.cc @@ -156,8 +156,8 @@ TEST_P(EnvoyQuicClientStreamTest, PostRequestAndResponse) { .WillOnce(Invoke([](const Http::ResponseTrailerMapPtr& headers) { Http::LowerCaseString key1("key1"); Http::LowerCaseString key2(":final-offset"); - EXPECT_EQ("value1", headers->get(key1)->value().getStringView()); - EXPECT_EQ(nullptr, headers->get(key2)); + EXPECT_EQ("value1", headers->get(key1)[0]->value().getStringView()); + EXPECT_TRUE(headers->get(key2).empty()); })); quic_stream_->OnStreamHeaderList(/*fin=*/true, trailers_.uncompressed_header_bytes(), trailers_); } @@ -205,8 +205,8 @@ TEST_P(EnvoyQuicClientStreamTest, OutOfOrderTrailers) { .WillOnce(Invoke([](const Http::ResponseTrailerMapPtr& headers) { Http::LowerCaseString key1("key1"); Http::LowerCaseString key2(":final-offset"); - EXPECT_EQ("value1", headers->get(key1)->value().getStringView()); - EXPECT_EQ(nullptr, headers->get(key2)); + EXPECT_EQ("value1", headers->get(key1)[0]->value().getStringView()); + EXPECT_TRUE(headers->get(key2).empty()); })); quic_stream_->OnStreamFrame(frame); } diff --git a/test/extensions/quic_listeners/quiche/envoy_quic_server_stream_test.cc b/test/extensions/quic_listeners/quiche/envoy_quic_server_stream_test.cc index c2fd31c6fdaa..42ba39344f4b 100644 --- a/test/extensions/quic_listeners/quiche/envoy_quic_server_stream_test.cc +++ b/test/extensions/quic_listeners/quiche/envoy_quic_server_stream_test.cc @@ -202,8 +202,8 @@ TEST_P(EnvoyQuicServerStreamTest, DecodeHeadersBodyAndTrailers) { .WillOnce(Invoke([](const Http::RequestTrailerMapPtr& headers) { Http::LowerCaseString key1("key1"); Http::LowerCaseString key2(":final-offset"); - EXPECT_EQ("value1", headers->get(key1)->value().getStringView()); - EXPECT_EQ(nullptr, headers->get(key2)); + EXPECT_EQ("value1", headers->get(key1)[0]->value().getStringView()); + EXPECT_TRUE(headers->get(key2).empty()); })); quic_stream_->OnStreamHeaderList(/*fin=*/true, trailers_.uncompressed_header_bytes(), trailers_); EXPECT_CALL(stream_callbacks_, onResetStream(_, _)); @@ -239,8 +239,8 @@ TEST_P(EnvoyQuicServerStreamTest, OutOfOrderTrailers) { .WillOnce(Invoke([](const Http::RequestTrailerMapPtr& headers) { Http::LowerCaseString key1("key1"); Http::LowerCaseString key2(":final-offset"); - EXPECT_EQ("value1", headers->get(key1)->value().getStringView()); - EXPECT_EQ(nullptr, headers->get(key2)); + EXPECT_EQ("value1", headers->get(key1)[0]->value().getStringView()); + EXPECT_TRUE(headers->get(key2).empty()); })); quic_stream_->OnStreamFrame(frame); } diff --git a/test/extensions/tracers/opencensus/tracer_test.cc b/test/extensions/tracers/opencensus/tracer_test.cc index 88ed7f2f5983..3a5e09fbf58d 100644 --- a/test/extensions/tracers/opencensus/tracer_test.cc +++ b/test/extensions/tracers/opencensus/tracer_test.cc @@ -174,10 +174,10 @@ MATCHER_P2(ContainHeader, header, expected_value, "contains the header " + PrintToString(header) + " with value " + PrintToString(expected_value)) { const auto found_value = arg.get(Http::LowerCaseString(header)); - if (found_value == nullptr) { + if (found_value.empty()) { return false; } - return found_value->value().getStringView() == expected_value; + return found_value[0]->value().getStringView() == expected_value; } // Given incoming headers, test that trace context propagation works and generates all the expected diff --git a/test/extensions/tracers/xray/tracer_test.cc b/test/extensions/tracers/xray/tracer_test.cc index 091dd8983d67..526cab8e9511 100644 --- a/test/extensions/tracers/xray/tracer_test.cc +++ b/test/extensions/tracers/xray/tracer_test.cc @@ -188,11 +188,11 @@ TEST_F(XRayTracerTest, SpanInjectContextHasXRayHeader) { absl::nullopt /*headers*/); Http::TestRequestHeaderMapImpl request_headers; span->injectContext(request_headers); - auto* header = request_headers.get(Http::LowerCaseString{XRayTraceHeader}); - ASSERT_NE(header, nullptr); - ASSERT_NE(header->value().getStringView().find("Root="), absl::string_view::npos); - ASSERT_NE(header->value().getStringView().find("Parent="), absl::string_view::npos); - ASSERT_NE(header->value().getStringView().find("Sampled=1"), absl::string_view::npos); + auto header = request_headers.get(Http::LowerCaseString{XRayTraceHeader}); + ASSERT_FALSE(header.empty()); + ASSERT_NE(header[0]->value().getStringView().find("Root="), absl::string_view::npos); + ASSERT_NE(header[0]->value().getStringView().find("Parent="), absl::string_view::npos); + ASSERT_NE(header[0]->value().getStringView().find("Sampled=1"), absl::string_view::npos); } TEST_F(XRayTracerTest, SpanInjectContextHasXRayHeaderNonSampled) { @@ -206,11 +206,11 @@ TEST_F(XRayTracerTest, SpanInjectContextHasXRayHeaderNonSampled) { auto span = tracer.createNonSampledSpan(); Http::TestRequestHeaderMapImpl request_headers; span->injectContext(request_headers); - auto* header = request_headers.get(Http::LowerCaseString{XRayTraceHeader}); - ASSERT_NE(header, nullptr); - ASSERT_NE(header->value().getStringView().find("Root="), absl::string_view::npos); - ASSERT_NE(header->value().getStringView().find("Parent="), absl::string_view::npos); - ASSERT_NE(header->value().getStringView().find("Sampled=0"), absl::string_view::npos); + auto header = request_headers.get(Http::LowerCaseString{XRayTraceHeader}); + ASSERT_FALSE(header.empty()); + ASSERT_NE(header[0]->value().getStringView().find("Root="), absl::string_view::npos); + ASSERT_NE(header[0]->value().getStringView().find("Parent="), absl::string_view::npos); + ASSERT_NE(header[0]->value().getStringView().find("Sampled=0"), absl::string_view::npos); } TEST_F(XRayTracerTest, TraceIDFormatTest) { diff --git a/test/extensions/tracers/zipkin/zipkin_tracer_impl_test.cc b/test/extensions/tracers/zipkin/zipkin_tracer_impl_test.cc index eb308bc76ef6..5e605999b671 100644 --- a/test/extensions/tracers/zipkin/zipkin_tracer_impl_test.cc +++ b/test/extensions/tracers/zipkin/zipkin_tracer_impl_test.cc @@ -475,9 +475,9 @@ TEST_F(ZipkinDriverTest, FlushSpansTimer) { TEST_F(ZipkinDriverTest, NoB3ContextSampledTrue) { setupValidDriver("HTTP_JSON_V1"); - EXPECT_EQ(nullptr, request_headers_.get(ZipkinCoreConstants::get().X_B3_SPAN_ID)); - EXPECT_EQ(nullptr, request_headers_.get(ZipkinCoreConstants::get().X_B3_TRACE_ID)); - EXPECT_EQ(nullptr, request_headers_.get(ZipkinCoreConstants::get().X_B3_SAMPLED)); + EXPECT_TRUE(request_headers_.get(ZipkinCoreConstants::get().X_B3_SPAN_ID).empty()); + EXPECT_TRUE(request_headers_.get(ZipkinCoreConstants::get().X_B3_TRACE_ID).empty()); + EXPECT_TRUE(request_headers_.get(ZipkinCoreConstants::get().X_B3_SAMPLED).empty()); Tracing::SpanPtr span = driver_->startSpan(config_, request_headers_, operation_name_, start_time_, {Tracing::Reason::Sampling, true}); @@ -489,9 +489,9 @@ TEST_F(ZipkinDriverTest, NoB3ContextSampledTrue) { TEST_F(ZipkinDriverTest, NoB3ContextSampledFalse) { setupValidDriver("HTTP_JSON_V1"); - EXPECT_EQ(nullptr, request_headers_.get(ZipkinCoreConstants::get().X_B3_SPAN_ID)); - EXPECT_EQ(nullptr, request_headers_.get(ZipkinCoreConstants::get().X_B3_TRACE_ID)); - EXPECT_EQ(nullptr, request_headers_.get(ZipkinCoreConstants::get().X_B3_SAMPLED)); + EXPECT_TRUE(request_headers_.get(ZipkinCoreConstants::get().X_B3_SPAN_ID).empty()); + EXPECT_TRUE(request_headers_.get(ZipkinCoreConstants::get().X_B3_TRACE_ID).empty()); + EXPECT_TRUE(request_headers_.get(ZipkinCoreConstants::get().X_B3_SAMPLED).empty()); Tracing::SpanPtr span = driver_->startSpan(config_, request_headers_, operation_name_, start_time_, {Tracing::Reason::Sampling, false}); @@ -507,7 +507,7 @@ TEST_F(ZipkinDriverTest, PropagateB3NoSampleDecisionSampleTrue) { Hex::uint64ToHex(generateRandom64())); request_headers_.addReferenceKey(ZipkinCoreConstants::get().X_B3_SPAN_ID, Hex::uint64ToHex(generateRandom64())); - EXPECT_EQ(nullptr, request_headers_.get(ZipkinCoreConstants::get().X_B3_SAMPLED)); + EXPECT_TRUE(request_headers_.get(ZipkinCoreConstants::get().X_B3_SAMPLED).empty()); Tracing::SpanPtr span = driver_->startSpan(config_, request_headers_, operation_name_, start_time_, {Tracing::Reason::Sampling, true}); @@ -523,7 +523,7 @@ TEST_F(ZipkinDriverTest, PropagateB3NoSampleDecisionSampleFalse) { Hex::uint64ToHex(generateRandom64())); request_headers_.addReferenceKey(ZipkinCoreConstants::get().X_B3_SPAN_ID, Hex::uint64ToHex(generateRandom64())); - EXPECT_EQ(nullptr, request_headers_.get(ZipkinCoreConstants::get().X_B3_SAMPLED)); + EXPECT_TRUE(request_headers_.get(ZipkinCoreConstants::get().X_B3_SAMPLED).empty()); Tracing::SpanPtr span = driver_->startSpan(config_, request_headers_, operation_name_, start_time_, {Tracing::Reason::Sampling, false}); @@ -535,8 +535,8 @@ TEST_F(ZipkinDriverTest, PropagateB3NoSampleDecisionSampleFalse) { TEST_F(ZipkinDriverTest, PropagateB3NotSampled) { setupValidDriver("HTTP_JSON_V1"); - EXPECT_EQ(nullptr, request_headers_.get(ZipkinCoreConstants::get().X_B3_SPAN_ID)); - EXPECT_EQ(nullptr, request_headers_.get(ZipkinCoreConstants::get().X_B3_TRACE_ID)); + EXPECT_TRUE(request_headers_.get(ZipkinCoreConstants::get().X_B3_SPAN_ID).empty()); + EXPECT_TRUE(request_headers_.get(ZipkinCoreConstants::get().X_B3_TRACE_ID).empty()); // Only context header set is B3 sampled to indicate trace should not be sampled request_headers_.addReferenceKey(ZipkinCoreConstants::get().X_B3_SAMPLED, NOT_SAMPLED); @@ -550,14 +550,14 @@ TEST_F(ZipkinDriverTest, PropagateB3NotSampled) { auto sampled_entry = request_headers_.get(ZipkinCoreConstants::get().X_B3_SAMPLED); // Check B3 sampled flag is set to not sample - EXPECT_EQ(NOT_SAMPLED, sampled_entry->value().getStringView()); + EXPECT_EQ(NOT_SAMPLED, sampled_entry[0]->value().getStringView()); } TEST_F(ZipkinDriverTest, PropagateB3NotSampledWithFalse) { setupValidDriver("HTTP_JSON_V1"); - EXPECT_EQ(nullptr, request_headers_.get(ZipkinCoreConstants::get().X_B3_SPAN_ID)); - EXPECT_EQ(nullptr, request_headers_.get(ZipkinCoreConstants::get().X_B3_TRACE_ID)); + EXPECT_TRUE(request_headers_.get(ZipkinCoreConstants::get().X_B3_SPAN_ID).empty()); + EXPECT_TRUE(request_headers_.get(ZipkinCoreConstants::get().X_B3_TRACE_ID).empty()); // Only context header set is B3 sampled to indicate trace should not be sampled (using legacy // 'false' value) @@ -572,14 +572,14 @@ TEST_F(ZipkinDriverTest, PropagateB3NotSampledWithFalse) { auto sampled_entry = request_headers_.get(ZipkinCoreConstants::get().X_B3_SAMPLED); // Check B3 sampled flag is set to not sample - EXPECT_EQ(NOT_SAMPLED, sampled_entry->value().getStringView()); + EXPECT_EQ(NOT_SAMPLED, sampled_entry[0]->value().getStringView()); } TEST_F(ZipkinDriverTest, PropagateB3SampledWithTrue) { setupValidDriver("HTTP_JSON_V1"); - EXPECT_EQ(nullptr, request_headers_.get(ZipkinCoreConstants::get().X_B3_SPAN_ID)); - EXPECT_EQ(nullptr, request_headers_.get(ZipkinCoreConstants::get().X_B3_TRACE_ID)); + EXPECT_TRUE(request_headers_.get(ZipkinCoreConstants::get().X_B3_SPAN_ID).empty()); + EXPECT_TRUE(request_headers_.get(ZipkinCoreConstants::get().X_B3_TRACE_ID).empty()); // Only context header set is B3 sampled to indicate trace should be sampled (using legacy // 'true' value) @@ -594,7 +594,7 @@ TEST_F(ZipkinDriverTest, PropagateB3SampledWithTrue) { auto sampled_entry = request_headers_.get(ZipkinCoreConstants::get().X_B3_SAMPLED); // Check B3 sampled flag is set to sample - EXPECT_EQ(SAMPLED, sampled_entry->value().getStringView()); + EXPECT_EQ(SAMPLED, sampled_entry[0]->value().getStringView()); } TEST_F(ZipkinDriverTest, PropagateB3SampleFalse) { @@ -829,7 +829,7 @@ TEST_F(ZipkinDriverTest, ExplicitlySetSampledFalse) { auto sampled_entry = request_headers_.get(ZipkinCoreConstants::get().X_B3_SAMPLED); // Check B3 sampled flag is set to not sample - EXPECT_EQ(NOT_SAMPLED, sampled_entry->value().getStringView()); + EXPECT_EQ(NOT_SAMPLED, sampled_entry[0]->value().getStringView()); } TEST_F(ZipkinDriverTest, ExplicitlySetSampledTrue) { @@ -846,7 +846,7 @@ TEST_F(ZipkinDriverTest, ExplicitlySetSampledTrue) { auto sampled_entry = request_headers_.get(ZipkinCoreConstants::get().X_B3_SAMPLED); // Check B3 sampled flag is set to sample - EXPECT_EQ(SAMPLED, sampled_entry->value().getStringView()); + EXPECT_EQ(SAMPLED, sampled_entry[0]->value().getStringView()); } TEST_F(ZipkinDriverTest, DuplicatedHeader) { diff --git a/test/integration/cds_integration_test.cc b/test/integration/cds_integration_test.cc index ba59ae02b60f..2fd76b992274 100644 --- a/test/integration/cds_integration_test.cc +++ b/test/integration/cds_integration_test.cc @@ -107,7 +107,7 @@ class CdsIntegrationTest : public Grpc::DeltaSotwIntegrationParamTest, public Ht std::string expected_method(sotwOrDelta() == Grpc::SotwOrDelta::Sotw ? "/envoy.api.v2.ClusterDiscoveryService/StreamClusters" : "/envoy.api.v2.ClusterDiscoveryService/DeltaClusters"); - EXPECT_EQ(xds_stream_->headers().get(path_string)->value(), expected_method); + EXPECT_EQ(xds_stream_->headers().get(path_string)[0]->value(), expected_method); } void acceptXdsConnection() { diff --git a/test/integration/filters/call_decodedata_once_filter.cc b/test/integration/filters/call_decodedata_once_filter.cc index 5e742dc8254d..520dbad96b82 100644 --- a/test/integration/filters/call_decodedata_once_filter.cc +++ b/test/integration/filters/call_decodedata_once_filter.cc @@ -16,13 +16,11 @@ class CallDecodeDataOnceFilter : public Http::PassThroughFilter { constexpr static char name[] = "call-decodedata-once-filter"; Http::FilterHeadersStatus decodeHeaders(Http::RequestHeaderMap& header_map, bool) override { - const Http::HeaderEntry* entry_content = - header_map.get(Envoy::Http::LowerCaseString("content_size")); - const Http::HeaderEntry* entry_added = - header_map.get(Envoy::Http::LowerCaseString("added_size")); - ASSERT(entry_content != nullptr && entry_added != nullptr); - content_size_ = std::stoul(std::string(entry_content->value().getStringView())); - added_size_ = std::stoul(std::string(entry_added->value().getStringView())); + const auto entry_content = header_map.get(Envoy::Http::LowerCaseString("content_size")); + const auto entry_added = header_map.get(Envoy::Http::LowerCaseString("added_size")); + ASSERT(!entry_content.empty() && !entry_added.empty()); + content_size_ = std::stoul(std::string(entry_content[0]->value().getStringView())); + added_size_ = std::stoul(std::string(entry_added[0]->value().getStringView())); return Http::FilterHeadersStatus::Continue; } diff --git a/test/integration/filters/decode_headers_return_stop_all_filter.cc b/test/integration/filters/decode_headers_return_stop_all_filter.cc index 133604822c8f..91edadb75153 100644 --- a/test/integration/filters/decode_headers_return_stop_all_filter.cc +++ b/test/integration/filters/decode_headers_return_stop_all_filter.cc @@ -27,29 +27,26 @@ class DecodeHeadersReturnStopAllFilter : public Http::PassThroughFilter { // Http::FilterHeadersStatus::StopAllIterationAndWatermark for headers. Triggers a timer to // continue iteration after 5s. Http::FilterHeadersStatus decodeHeaders(Http::RequestHeaderMap& header_map, bool) override { - const Http::HeaderEntry* entry_content = - header_map.get(Envoy::Http::LowerCaseString("content_size")); - const Http::HeaderEntry* entry_added = - header_map.get(Envoy::Http::LowerCaseString("added_size")); - ASSERT(entry_content != nullptr && entry_added != nullptr); - content_size_ = std::stoul(std::string(entry_content->value().getStringView())); - added_size_ = std::stoul(std::string(entry_added->value().getStringView())); - const Http::HeaderEntry* entry_is_first_trigger = + const auto entry_content = header_map.get(Envoy::Http::LowerCaseString("content_size")); + const auto entry_added = header_map.get(Envoy::Http::LowerCaseString("added_size")); + ASSERT(!entry_content.empty() && !entry_added.empty()); + content_size_ = std::stoul(std::string(entry_content[0]->value().getStringView())); + added_size_ = std::stoul(std::string(entry_added[0]->value().getStringView())); + const auto entry_is_first_trigger = header_map.get(Envoy::Http::LowerCaseString("is_first_trigger")); - is_first_trigger_ = entry_is_first_trigger != nullptr; + is_first_trigger_ = !entry_is_first_trigger.empty(); // Remove "first_trigger" headers so that if the filter is registered twice in a filter chain, // it would act differently. header_map.remove(Http::LowerCaseString("is_first_trigger")); createTimerForContinue(); - const Http::HeaderEntry* entry_buffer = - header_map.get(Envoy::Http::LowerCaseString("buffer_limit")); - if (entry_buffer == nullptr || !is_first_trigger_) { + const auto entry_buffer = header_map.get(Envoy::Http::LowerCaseString("buffer_limit")); + if (entry_buffer.empty() || !is_first_trigger_) { return Http::FilterHeadersStatus::StopAllIterationAndBuffer; } else { watermark_enabled_ = true; - buffer_limit_ = std::stoul(std::string(entry_buffer->value().getStringView())); + buffer_limit_ = std::stoul(std::string(entry_buffer[0]->value().getStringView())); decoder_callbacks_->setDecoderBufferLimit(buffer_limit_); header_map.remove(Http::LowerCaseString("buffer_limit")); return Http::FilterHeadersStatus::StopAllIterationAndWatermark; diff --git a/test/integration/filters/encode_headers_return_stop_all_filter.cc b/test/integration/filters/encode_headers_return_stop_all_filter.cc index 88a409501cbe..2254204ec100 100644 --- a/test/integration/filters/encode_headers_return_stop_all_filter.cc +++ b/test/integration/filters/encode_headers_return_stop_all_filter.cc @@ -27,13 +27,11 @@ class EncodeHeadersReturnStopAllFilter : public Http::PassThroughFilter { // Http::FilterHeadersStatus::StopAllIterationAndWatermark for headers. Triggers a timer to // continue iteration after 5s. Http::FilterHeadersStatus encodeHeaders(Http::ResponseHeaderMap& header_map, bool) override { - const Http::HeaderEntry* entry_content = - header_map.get(Envoy::Http::LowerCaseString("content_size")); - const Http::HeaderEntry* entry_added = - header_map.get(Envoy::Http::LowerCaseString("added_size")); - ASSERT(entry_content != nullptr && entry_added != nullptr); - content_size_ = std::stoul(std::string(entry_content->value().getStringView())); - added_size_ = std::stoul(std::string(entry_added->value().getStringView())); + const auto entry_content = header_map.get(Envoy::Http::LowerCaseString("content_size")); + const auto entry_added = header_map.get(Envoy::Http::LowerCaseString("added_size")); + ASSERT(!entry_content.empty() && !entry_added.empty()); + content_size_ = std::stoul(std::string(entry_content[0]->value().getStringView())); + added_size_ = std::stoul(std::string(entry_added[0]->value().getStringView())); createTimerForContinue(); @@ -41,14 +39,13 @@ class EncodeHeadersReturnStopAllFilter : public Http::PassThroughFilter { Http::MetadataMapPtr metadata_map_ptr = std::make_unique(metadata_map); encoder_callbacks_->addEncodedMetadata(std::move(metadata_map_ptr)); - const Http::HeaderEntry* entry_buffer = - header_map.get(Envoy::Http::LowerCaseString("buffer_limit")); - if (entry_buffer == nullptr) { + const auto entry_buffer = header_map.get(Envoy::Http::LowerCaseString("buffer_limit")); + if (entry_buffer.empty()) { return Http::FilterHeadersStatus::StopAllIterationAndBuffer; } else { watermark_enabled_ = true; encoder_callbacks_->setEncoderBufferLimit( - std::stoul(std::string(entry_buffer->value().getStringView()))); + std::stoul(std::string(entry_buffer[0]->value().getStringView()))); return Http::FilterHeadersStatus::StopAllIterationAndWatermark; } } diff --git a/test/integration/filters/metadata_stop_all_filter.cc b/test/integration/filters/metadata_stop_all_filter.cc index f119c38cc9ab..c7da73957417 100644 --- a/test/integration/filters/metadata_stop_all_filter.cc +++ b/test/integration/filters/metadata_stop_all_filter.cc @@ -22,10 +22,9 @@ class MetadataStopAllFilter : public Http::PassThroughFilter { constexpr static char name[] = "metadata-stop-all-filter"; Http::FilterHeadersStatus decodeHeaders(Http::RequestHeaderMap& header_map, bool) override { - const Http::HeaderEntry* entry_content = - header_map.get(Envoy::Http::LowerCaseString("content_size")); - ASSERT(entry_content != nullptr); - content_size_ = std::stoul(std::string(entry_content->value().getStringView())); + const auto entry_content = header_map.get(Envoy::Http::LowerCaseString("content_size")); + ASSERT(!entry_content.empty()); + content_size_ = std::stoul(std::string(entry_content[0]->value().getStringView())); createTimerForContinue(); diff --git a/test/integration/header_prefix_integration_test.cc b/test/integration/header_prefix_integration_test.cc index e2e47831a27c..52ca839c7607 100644 --- a/test/integration/header_prefix_integration_test.cc +++ b/test/integration/header_prefix_integration_test.cc @@ -35,13 +35,15 @@ TEST_P(HeaderPrefixIntegrationTest, CustomHeaderPrefix) { auto response = sendRequestAndWaitForResponse(default_request_headers_, 0, default_response_headers_, 0); - EXPECT_TRUE(response->headers().get( - Envoy::Http::LowerCaseString{"x-custom-upstream-service-time"}) != nullptr); + EXPECT_FALSE(response->headers() + .get(Envoy::Http::LowerCaseString{"x-custom-upstream-service-time"}) + .empty()); EXPECT_EQ("x-custom-upstream-service-time", response->headers().EnvoyUpstreamServiceTime()->key().getStringView()); - EXPECT_TRUE(upstream_request_->headers().get( - Envoy::Http::LowerCaseString{"x-custom-expected-rq-timeout-ms"}) != nullptr); + EXPECT_FALSE(upstream_request_->headers() + .get(Envoy::Http::LowerCaseString{"x-custom-expected-rq-timeout-ms"}) + .empty()); EXPECT_EQ("x-custom-expected-rq-timeout-ms", upstream_request_->headers().EnvoyExpectedRequestTimeoutMs()->key().getStringView()); } diff --git a/test/integration/http2_integration_test.cc b/test/integration/http2_integration_test.cc index 188ae469cdf6..aeacee26f724 100644 --- a/test/integration/http2_integration_test.cc +++ b/test/integration/http2_integration_test.cc @@ -1382,9 +1382,11 @@ TEST_P(Http2RingHashIntegrationTest, CookieRoutingNoCookieNoTtl) { {":authority", "host"}}, [&](IntegrationStreamDecoder& response) { EXPECT_EQ("200", response.headers().getStatusValue()); - EXPECT_TRUE(response.headers().get(Http::Headers::get().SetCookie) == nullptr); - served_by.insert(std::string( - response.headers().get(Http::LowerCaseString("x-served-by"))->value().getStringView())); + EXPECT_TRUE(response.headers().get(Http::Headers::get().SetCookie).empty()); + served_by.insert(std::string(response.headers() + .get(Http::LowerCaseString("x-served-by"))[0] + ->value() + .getStringView())); }); EXPECT_EQ(served_by.size(), num_upstreams_); } @@ -1413,7 +1415,7 @@ TEST_P(Http2RingHashIntegrationTest, CookieRoutingNoCookieWithNonzeroTtlSet) { [&](IntegrationStreamDecoder& response) { EXPECT_EQ("200", response.headers().getStatusValue()); std::string value( - response.headers().get(Http::Headers::get().SetCookie)->value().getStringView()); + response.headers().get(Http::Headers::get().SetCookie)[0]->value().getStringView()); set_cookies.insert(value); EXPECT_THAT(value, MatchesRegex("foo=.*; Max-Age=15; HttpOnly")); }); @@ -1444,7 +1446,7 @@ TEST_P(Http2RingHashIntegrationTest, CookieRoutingNoCookieWithZeroTtlSet) { [&](IntegrationStreamDecoder& response) { EXPECT_EQ("200", response.headers().getStatusValue()); std::string value( - response.headers().get(Http::Headers::get().SetCookie)->value().getStringView()); + response.headers().get(Http::Headers::get().SetCookie)[0]->value().getStringView()); set_cookies.insert(value); EXPECT_THAT(value, MatchesRegex("^foo=.*$")); }); @@ -1474,9 +1476,11 @@ TEST_P(Http2RingHashIntegrationTest, CookieRoutingWithCookieNoTtl) { {":authority", "host"}}, [&](IntegrationStreamDecoder& response) { EXPECT_EQ("200", response.headers().getStatusValue()); - EXPECT_TRUE(response.headers().get(Http::Headers::get().SetCookie) == nullptr); - served_by.insert(std::string( - response.headers().get(Http::LowerCaseString("x-served-by"))->value().getStringView())); + EXPECT_TRUE(response.headers().get(Http::Headers::get().SetCookie).empty()); + served_by.insert(std::string(response.headers() + .get(Http::LowerCaseString("x-served-by"))[0] + ->value() + .getStringView())); }); EXPECT_EQ(served_by.size(), 1); } @@ -1505,9 +1509,11 @@ TEST_P(Http2RingHashIntegrationTest, CookieRoutingWithCookieWithTtlSet) { {":authority", "host"}}, [&](IntegrationStreamDecoder& response) { EXPECT_EQ("200", response.headers().getStatusValue()); - EXPECT_TRUE(response.headers().get(Http::Headers::get().SetCookie) == nullptr); - served_by.insert(std::string( - response.headers().get(Http::LowerCaseString("x-served-by"))->value().getStringView())); + EXPECT_TRUE(response.headers().get(Http::Headers::get().SetCookie).empty()); + served_by.insert(std::string(response.headers() + .get(Http::LowerCaseString("x-served-by"))[0] + ->value() + .getStringView())); }); EXPECT_EQ(served_by.size(), 1); } diff --git a/test/integration/http_integration.cc b/test/integration/http_integration.cc index 611f8df405cb..8b28b8a22bce 100644 --- a/test/integration/http_integration.cc +++ b/test/integration/http_integration.cc @@ -373,10 +373,10 @@ void HttpIntegrationTest::verifyResponse(IntegrationStreamDecoderPtr response, EXPECT_EQ(response_code, response->headers().getStatusValue()); expected_headers.iterate([response_headers = &response->headers()]( const Http::HeaderEntry& header) -> Http::HeaderMap::Iterate { - const Http::HeaderEntry* entry = + const auto entry = response_headers->get(Http::LowerCaseString{std::string(header.key().getStringView())}); - EXPECT_NE(entry, nullptr); - EXPECT_EQ(header.value().getStringView(), entry->value().getStringView()); + EXPECT_FALSE(entry.empty()); + EXPECT_EQ(header.value().getStringView(), entry[0]->value().getStringView()); return Http::HeaderMap::Iterate::Continue; }); @@ -849,12 +849,13 @@ void HttpIntegrationTest::testEnvoyHandling100Continue(bool additional_continue_ codec_client_->sendData(*request_encoder_, 10, true); ASSERT_TRUE(upstream_request_->waitForEndStream(*dispatcher_)); // Verify the Expect header is stripped. - EXPECT_EQ(nullptr, upstream_request_->headers().get(Http::Headers::get().Expect)); + EXPECT_TRUE(upstream_request_->headers().get(Http::Headers::get().Expect).empty()); if (via.empty()) { - EXPECT_EQ(nullptr, upstream_request_->headers().get(Http::Headers::get().Via)); + EXPECT_TRUE(upstream_request_->headers().get(Http::Headers::get().Via).empty()); } else { - EXPECT_EQ(via, - upstream_request_->headers().get(Http::Headers::get().Via)->value().getStringView()); + EXPECT_EQ( + via, + upstream_request_->headers().get(Http::Headers::get().Via)[0]->value().getStringView()); } if (additional_continue_from_upstream) { @@ -1186,7 +1187,7 @@ void HttpIntegrationTest::testDownstreamResetBeforeResponseComplete() { codec_client_->sendData(*request_encoder_, 0, true); waitForNextUpstreamRequest(); - EXPECT_EQ(upstream_request_->headers().get(Http::Headers::get().Cookie)->value(), "a=b; c=d"); + EXPECT_EQ(upstream_request_->headers().get(Http::Headers::get().Cookie)[0]->value(), "a=b; c=d"); upstream_request_->encodeHeaders(default_response_headers_, false); upstream_request_->encodeData(512, false); diff --git a/test/integration/http_subset_lb_integration_test.cc b/test/integration/http_subset_lb_integration_test.cc index cd275c20a7c3..3094db9cf42e 100644 --- a/test/integration/http_subset_lb_integration_test.cc +++ b/test/integration/http_subset_lb_integration_test.cc @@ -159,14 +159,14 @@ class HttpSubsetLbIntegrationTest // Expect a response from a host in the correct subset. EXPECT_EQ(response->headers() - .get(Envoy::Http::LowerCaseString{host_type_header_}) + .get(Envoy::Http::LowerCaseString{host_type_header_})[0] ->value() .getStringView(), expected_host_type); // Record the upstream address. hosts.emplace(response->headers() - .get(Envoy::Http::LowerCaseString{host_header_}) + .get(Envoy::Http::LowerCaseString{host_header_})[0] ->value() .getStringView()); diff --git a/test/integration/idle_timeout_integration_test.cc b/test/integration/idle_timeout_integration_test.cc index 1f549adafddf..d347849950ee 100644 --- a/test/integration/idle_timeout_integration_test.cc +++ b/test/integration/idle_timeout_integration_test.cc @@ -183,8 +183,8 @@ TEST_P(IdleTimeoutIntegrationTest, PerStreamIdleTimeoutAfterDownstreamHeaders) { EXPECT_TRUE(response->complete()); EXPECT_EQ("408", response->headers().getStatusValue()); auto foo = Http::LowerCaseString("foo"); - ASSERT_TRUE(response->headers().get(foo) != nullptr); - EXPECT_EQ("bar", response->headers().get(foo)->value().getStringView()); + ASSERT_FALSE(response->headers().get(foo).empty()); + EXPECT_EQ("bar", response->headers().get(foo)[0]->value().getStringView()); EXPECT_EQ("stream timeout", response->body()); EXPECT_THAT(waitForAccessLog(access_log_name_), HasSubstr("stream_idle_timeout")); diff --git a/test/integration/integration_test.cc b/test/integration/integration_test.cc index 594f5ac656c5..3f91991cee94 100644 --- a/test/integration/integration_test.cc +++ b/test/integration/integration_test.cc @@ -179,7 +179,7 @@ TEST_P(IntegrationTest, RouterDirectResponseWithBody) { ASSERT_TRUE(response->complete()); EXPECT_EQ("200", response->headers().getStatusValue()); EXPECT_EQ("example-value", response->headers() - .get(Envoy::Http::LowerCaseString("x-additional-header")) + .get(Envoy::Http::LowerCaseString("x-additional-header"))[0] ->value() .getStringView()); EXPECT_EQ("text/html", response->headers().getContentTypeValue()); @@ -223,7 +223,7 @@ TEST_P(IntegrationTest, RouterDirectResponseEmptyBody) { ASSERT_TRUE(response->complete()); EXPECT_EQ("200", response->headers().getStatusValue()); EXPECT_EQ("example-value", response->headers() - .get(Envoy::Http::LowerCaseString("x-additional-header")) + .get(Envoy::Http::LowerCaseString("x-additional-header"))[0] ->value() .getStringView()); // Content-type header is removed. @@ -709,12 +709,12 @@ TEST_P(IntegrationTest, TestInlineHeaders) { ASSERT_TRUE(upstream_headers != nullptr); EXPECT_EQ(upstream_headers->Host()->value(), "foo.com"); EXPECT_EQ(upstream_headers->get_("User-Agent"), "public,123"); - ASSERT_TRUE(upstream_headers->get(Envoy::Http::LowerCaseString("foo")) != nullptr); + ASSERT_FALSE(upstream_headers->get(Envoy::Http::LowerCaseString("foo")).empty()); EXPECT_EQ("bar", - upstream_headers->get(Envoy::Http::LowerCaseString("foo"))->value().getStringView()); - ASSERT_TRUE(upstream_headers->get(Envoy::Http::LowerCaseString("eep")) != nullptr); + upstream_headers->get(Envoy::Http::LowerCaseString("foo"))[0]->value().getStringView()); + ASSERT_FALSE(upstream_headers->get(Envoy::Http::LowerCaseString("eep")).empty()); EXPECT_EQ("baz", - upstream_headers->get(Envoy::Http::LowerCaseString("eep"))->value().getStringView()); + upstream_headers->get(Envoy::Http::LowerCaseString("eep"))[0]->value().getStringView()); } // Verify for HTTP/1.0 a keep-alive header results in no connection: close. diff --git a/test/integration/local_reply_integration_test.cc b/test/integration/local_reply_integration_test.cc index dacd7fcad033..d89669f0cb76 100644 --- a/test/integration/local_reply_integration_test.cc +++ b/test/integration/local_reply_integration_test.cc @@ -79,7 +79,8 @@ TEST_P(LocalReplyIntegrationTest, MapStatusCodeAndFormatToJson) { EXPECT_EQ("application/json", response->headers().ContentType()->value().getStringView()); EXPECT_EQ("150", response->headers().ContentLength()->value().getStringView()); EXPECT_EQ("550", response->headers().Status()->value().getStringView()); - EXPECT_EQ("bar", response->headers().get(Http::LowerCaseString("foo"))->value().getStringView()); + EXPECT_EQ("bar", + response->headers().get(Http::LowerCaseString("foo"))[0]->value().getStringView()); // Check if returned json is same as expected EXPECT_TRUE(TestUtility::jsonStringEqual(response->body(), expected_body)); } @@ -210,7 +211,8 @@ TEST_P(LocalReplyIntegrationTest, MapStatusCodeAndFormatToJsonForFirstMatchingFi EXPECT_EQ("text/plain", response->headers().ContentType()->value().getStringView()); EXPECT_EQ("24", response->headers().ContentLength()->value().getStringView()); EXPECT_EQ("551", response->headers().Status()->value().getStringView()); - EXPECT_EQ("bar", response->headers().get(Http::LowerCaseString("foo"))->value().getStringView()); + EXPECT_EQ("bar", + response->headers().get(Http::LowerCaseString("foo"))[0]->value().getStringView()); // Check if returned json is same as expected EXPECT_EQ(response->body(), expected_body); } diff --git a/test/integration/protocol_integration_test.cc b/test/integration/protocol_integration_test.cc index 84d928d19dfd..39e5b2738e87 100644 --- a/test/integration/protocol_integration_test.cc +++ b/test/integration/protocol_integration_test.cc @@ -154,7 +154,7 @@ TEST_P(ProtocolIntegrationTest, RouterRedirect) { ASSERT_TRUE(response->complete()); EXPECT_EQ("301", response->headers().getStatusValue()); EXPECT_EQ("https://www.redirect.com/foo", - response->headers().get(Http::Headers::get().Location)->value().getStringView()); + response->headers().get(Http::Headers::get().Location)[0]->value().getStringView()); } TEST_P(ProtocolIntegrationTest, UnknownResponsecode) { @@ -303,7 +303,7 @@ name: add-trailers-filter if (upstreamProtocol() == FakeHttpConnection::Type::HTTP2) { EXPECT_EQ("decode", upstream_request_->trailers() - ->get(Http::LowerCaseString("grpc-message")) + ->get(Http::LowerCaseString("grpc-message"))[0] ->value() .getStringView()); } @@ -330,7 +330,7 @@ TEST_P(ProtocolIntegrationTest, ResponseWithHostHeader) { EXPECT_TRUE(response->complete()); EXPECT_EQ("200", response->headers().getStatusValue()); EXPECT_EQ("host", - response->headers().get(Http::LowerCaseString("host"))->value().getStringView()); + response->headers().get(Http::LowerCaseString("host"))[0]->value().getStringView()); } // Regression test for https://github.com/envoyproxy/envoy/issues/10270 @@ -351,7 +351,7 @@ TEST_P(ProtocolIntegrationTest, LongHeaderValueWithSpaces) { {"longrequestvalue", long_header_value_with_inner_lws}}); waitForNextUpstreamRequest(); EXPECT_EQ(long_header_value_with_inner_lws, upstream_request_->headers() - .get(Http::LowerCaseString("longrequestvalue")) + .get(Http::LowerCaseString("longrequestvalue"))[0] ->value() .getStringView()); upstream_request_->encodeHeaders( @@ -363,10 +363,12 @@ TEST_P(ProtocolIntegrationTest, LongHeaderValueWithSpaces) { EXPECT_TRUE(response->complete()); EXPECT_EQ("200", response->headers().getStatusValue()); EXPECT_EQ("host", - response->headers().get(Http::LowerCaseString("host"))->value().getStringView()); - EXPECT_EQ( - long_header_value_with_inner_lws, - response->headers().get(Http::LowerCaseString("longresponsevalue"))->value().getStringView()); + response->headers().get(Http::LowerCaseString("host"))[0]->value().getStringView()); + EXPECT_EQ(long_header_value_with_inner_lws, + response->headers() + .get(Http::LowerCaseString("longresponsevalue"))[0] + ->value() + .getStringView()); } TEST_P(ProtocolIntegrationTest, Retry) { @@ -898,8 +900,8 @@ TEST_P(ProtocolIntegrationTest, HittingEncoderFilterLimit) { EXPECT_EQ("500", response->headers().getStatusValue()); // Regression test all sendLocalReply paths add route-requested headers. auto foo = Http::LowerCaseString("foo"); - ASSERT_TRUE(response->headers().get(foo) != nullptr); - EXPECT_EQ("bar", response->headers().get(foo)->value().getStringView()); + ASSERT_FALSE(response->headers().get(foo).empty()); + EXPECT_EQ("bar", response->headers().get(foo)[0]->value().getStringView()); // Regression test https://github.com/envoyproxy/envoy/issues/9881 by making // sure this path does standard HCM header transformations. @@ -1722,11 +1724,10 @@ TEST_P(ProtocolIntegrationTest, MultipleSetCookies) { ASSERT_TRUE(response->complete()); EXPECT_EQ("200", response->headers().getStatusValue()); - std::vector out; - Http::HeaderUtility::getAllOfHeader(response->headers(), "set-cookie", out); + const auto out = response->headers().get(Http::LowerCaseString("set-cookie")); ASSERT_EQ(out.size(), 2); - ASSERT_EQ(out[0], "foo"); - ASSERT_EQ(out[1], "bar"); + ASSERT_EQ(out[0]->value().getStringView(), "foo"); + ASSERT_EQ(out[1]->value().getStringView(), "bar"); } // Resets the downstream stream immediately and verifies that we clean up everything. diff --git a/test/integration/sds_generic_secret_integration_test.cc b/test/integration/sds_generic_secret_integration_test.cc index 719bc0cc4f39..ac466c6a40ec 100644 --- a/test/integration/sds_generic_secret_integration_test.cc +++ b/test/integration/sds_generic_secret_integration_test.cc @@ -147,9 +147,10 @@ TEST_P(SdsGenericSecretIntegrationTest, FilterFetchSuccess) { EXPECT_TRUE(upstream_request_->complete()); EXPECT_EQ(0U, upstream_request_->bodyLength()); - EXPECT_EQ( - "DUMMY_AES_128_KEY", - upstream_request_->headers().get(Http::LowerCaseString("secret"))->value().getStringView()); + EXPECT_EQ("DUMMY_AES_128_KEY", upstream_request_->headers() + .get(Http::LowerCaseString("secret"))[0] + ->value() + .getStringView()); } } // namespace Envoy diff --git a/test/integration/tcp_tunneling_integration_test.cc b/test/integration/tcp_tunneling_integration_test.cc index 11a14a182416..5c4fbdf022e4 100644 --- a/test/integration/tcp_tunneling_integration_test.cc +++ b/test/integration/tcp_tunneling_integration_test.cc @@ -218,11 +218,11 @@ TEST_P(ProxyingConnectIntegrationTest, ProxyConnect) { result = fake_upstream_connection_->waitForNewStream(*dispatcher_, upstream_request_); RELEASE_ASSERT(result, result.message()); ASSERT_TRUE(upstream_request_->waitForHeadersComplete()); - EXPECT_EQ(upstream_request_->headers().get(Http::Headers::get().Method)->value(), "CONNECT"); + EXPECT_EQ(upstream_request_->headers().get(Http::Headers::get().Method)[0]->value(), "CONNECT"); if (upstreamProtocol() == FakeHttpConnection::Type::HTTP1) { - EXPECT_TRUE(upstream_request_->headers().get(Http::Headers::get().Protocol) == nullptr); + EXPECT_TRUE(upstream_request_->headers().get(Http::Headers::get().Protocol).empty()); } else { - EXPECT_EQ(upstream_request_->headers().get(Http::Headers::get().Protocol)->value(), + EXPECT_EQ(upstream_request_->headers().get(Http::Headers::get().Protocol)[0]->value(), "bytestream"); } diff --git a/test/test_common/utility.cc b/test/test_common/utility.cc index a0a4814f37c8..81f2f79611dd 100644 --- a/test/test_common/utility.cc +++ b/test/test_common/utility.cc @@ -71,9 +71,10 @@ bool TestUtility::headerMapEqualIgnoreOrder(const Http::HeaderMap& lhs, bool equal = true; rhs.iterate([&lhs, &equal](const Http::HeaderEntry& header) -> Http::HeaderMap::Iterate { - const Http::HeaderEntry* entry = - lhs.get(Http::LowerCaseString(std::string(header.key().getStringView()))); - if (entry == nullptr || (entry->value() != header.value().getStringView())) { + // TODO(mattklein123): Handle multiple headers. + auto entry = lhs.get(Http::LowerCaseString(std::string(header.key().getStringView()))); + if (entry.empty() || entry.size() > 1 || + (entry[0]->value() != header.value().getStringView())) { equal = false; return Http::HeaderMap::Iterate::Break; } diff --git a/test/test_common/utility.h b/test/test_common/utility.h index 389b95f65929..3dc15c8ccac0 100644 --- a/test/test_common/utility.h +++ b/test/test_common/utility.h @@ -880,15 +880,16 @@ template class TestHeaderMapImplBase : public Inte } std::string get_(const std::string& key) const { return get_(LowerCaseString(key)); } std::string get_(const LowerCaseString& key) const { - const HeaderEntry* header = get(key); - if (!header) { + // TODO(mattklein123): Possibly allow getting additional headers beyond the first. + auto headers = get(key); + if (headers.empty()) { return EMPTY_STRING; } else { - return std::string(header->value().getStringView()); + return std::string(headers[0]->value().getStringView()); } } - bool has(const std::string& key) const { return get(LowerCaseString(key)) != nullptr; } - bool has(const LowerCaseString& key) const { return get(key) != nullptr; } + bool has(const std::string& key) const { return !get(LowerCaseString(key)).empty(); } + bool has(const LowerCaseString& key) const { return !get(key).empty(); } size_t remove(const std::string& key) { return remove(LowerCaseString(key)); } // HeaderMap @@ -934,12 +935,9 @@ template class TestHeaderMapImplBase : public Inte header_map_->verifyByteSizeInternalForTest(); } uint64_t byteSize() const override { return header_map_->byteSize(); } - const HeaderEntry* get(const LowerCaseString& key) const override { + HeaderMap::GetResult get(const LowerCaseString& key) const override { return header_map_->get(key); } - HeaderMap::GetResult getAll(const LowerCaseString& key) const override { - return header_map_->getAll(key); - } void iterate(HeaderMap::ConstIterateCb cb) const override { header_map_->iterate(cb); } void iterateReverse(HeaderMap::ConstIterateCb cb) const override { header_map_->iterateReverse(cb); diff --git a/test/tools/router_check/router.cc b/test/tools/router_check/router.cc index 87ad88f40d3f..3b5178ff87fa 100644 --- a/test/tools/router_check/router.cc +++ b/test/tools/router_check/router.cc @@ -51,8 +51,9 @@ toString(envoy::config::route::v3::HeaderMatcher::HeaderMatchSpecifierCase speci NOT_REACHED_GCOVR_EXCL_LINE; } -const std::string toString(const Envoy::Http::HeaderEntry* entry) { - return entry == nullptr ? "NULL" : std::string(entry->value().getStringView()); +const std::string toString(const Envoy::Http::HeaderMap::GetResult& entry) { + // TODO(mattklein123): Print multiple header values. + return entry.empty() ? "NULL" : std::string(entry[0]->value().getStringView()); } } // namespace