diff --git a/CODEOWNERS b/CODEOWNERS index 4f064d203fb2..e0d262de1d4d 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -293,6 +293,8 @@ extensions/filters/http/oauth2 @derekargueta @mattklein123 # Thrift /*/extensions/filters/network/thrift_proxy @zuercher @JuniorHsu /*/extensions/health_checkers/thrift @zuercher @JuniorHsu +# Thrift to metadata +/*/extensions/filters/http/thrift_to_metadata @JuniorHsu @zuercher # IP tagging /*/extensions/filters/http/ip_tagging @alyssawilk @JuniorHsu # Header to metadata diff --git a/api/BUILD b/api/BUILD index 57bb807f2d0a..1ac8e46d467c 100644 --- a/api/BUILD +++ b/api/BUILD @@ -215,6 +215,7 @@ proto_library( "//envoy/extensions/filters/http/set_metadata/v3:pkg", "//envoy/extensions/filters/http/stateful_session/v3:pkg", "//envoy/extensions/filters/http/tap/v3:pkg", + "//envoy/extensions/filters/http/thrift_to_metadata/v3:pkg", "//envoy/extensions/filters/http/upstream_codec/v3:pkg", "//envoy/extensions/filters/http/wasm/v3:pkg", "//envoy/extensions/filters/listener/http_inspector/v3:pkg", diff --git a/api/envoy/extensions/filters/http/thrift_to_metadata/v3/BUILD b/api/envoy/extensions/filters/http/thrift_to_metadata/v3/BUILD new file mode 100644 index 000000000000..f592dc73ad98 --- /dev/null +++ b/api/envoy/extensions/filters/http/thrift_to_metadata/v3/BUILD @@ -0,0 +1,13 @@ +# DO NOT EDIT. This file is generated by tools/proto_format/proto_sync.py. + +load("@envoy_api//bazel:api_build_system.bzl", "api_proto_package") + +licenses(["notice"]) # Apache 2 + +api_proto_package( + deps = [ + "//envoy/extensions/filters/network/thrift_proxy/v3:pkg", + "@com_github_cncf_xds//udpa/annotations:pkg", + "@com_github_cncf_xds//xds/annotations/v3:pkg", + ], +) diff --git a/api/envoy/extensions/filters/http/thrift_to_metadata/v3/thrift_to_metadata.proto b/api/envoy/extensions/filters/http/thrift_to_metadata/v3/thrift_to_metadata.proto new file mode 100644 index 000000000000..9450387aaee2 --- /dev/null +++ b/api/envoy/extensions/filters/http/thrift_to_metadata/v3/thrift_to_metadata.proto @@ -0,0 +1,190 @@ +syntax = "proto3"; + +package envoy.extensions.filters.http.thrift_to_metadata.v3; + +import "envoy/extensions/filters/network/thrift_proxy/v3/thrift_proxy.proto"; + +import "google/protobuf/struct.proto"; + +import "xds/annotations/v3/status.proto"; + +import "udpa/annotations/status.proto"; +import "validate/validate.proto"; + +option java_package = "io.envoyproxy.envoy.extensions.filters.http.thrift_to_metadata.v3"; +option java_outer_classname = "ThriftToMetadataProto"; +option java_multiple_files = true; +option go_package = "github.com/envoyproxy/go-control-plane/envoy/extensions/filters/http/thrift_to_metadata/v3;thrift_to_metadatav3"; +option (udpa.annotations.file_status).package_version_status = ACTIVE; +option (xds.annotations.v3.file_status).work_in_progress = true; + +// [#protodoc-title: Thrift-To-Metadata Filter] +// +// The Thrift to Metadata filter serves for thrift over HTTP traffic, expecting serialized +// Thrift request and response bodies in the HTTP payload. It extracts *thrift metadata* from the +// HTTP body and put them into the *filter metadata*. This is useful for matching load balancer +// subsets, logging, etc. +// +// Thrift to Metadata :ref:`configuration overview `. +// [#extension: envoy.filters.http.thrift_to_metadata] + +enum Field { + // The Thrift method name, string value. + METHOD_NAME = 0; + + // The Thrift protocol name, string value. Values are "binary", "binary/non-strict", and "compact", with "(auto)" suffix if + // :ref:`protocol ` + // is set to :ref:`AUTO_PROTOCOL` + PROTOCOL = 1; + + // The Thrift transport name, string value. Values are "framed", "header", and "unframed", with "(auto)" suffix if + // :ref:`transport ` + // is set to :ref:`AUTO_TRANSPORT` + TRANSPORT = 2; + + // The Thrift message type, singed 16-bit integer value. + HEADER_FLAGS = 3; + + // The Thrift sequence ID, singed 32-bit integer value. + SEQUENCE_ID = 4; + + // The Thrift message type, string value. Values in request are "call" and "oneway", and in response are "reply" and "exception". + MESSAGE_TYPE = 5; + + // The Thrift reply type, string value. This is only valid for response rules. Values are "success" and "error". + REPLY_TYPE = 6; +} + +message KeyValuePair { + // The namespace — if this is empty, the filter's namespace will be used. + string metadata_namespace = 1; + + // The key to use within the namespace. + string key = 2 [(validate.rules).string = {min_len: 1}]; + + // When used for on_present case, if value is non-empty it'll be used instead + // of the field value. + // + // When used for on_missing case, a non-empty value must be provided. + google.protobuf.Value value = 3; +} + +message FieldSelector { + option (xds.annotations.v3.message_status).work_in_progress = true; + + // field name to log + string name = 1 [(validate.rules).string = {min_len: 1}]; + + // field id to match + int32 id = 2 [(validate.rules).int32 = {lte: 32767 gte: -32768}]; + + // next node of the field selector + FieldSelector child = 3; +} + +// [#next-free-field: 6] +message Rule { + // The field to match on. If set, takes precedence over field_selector. + Field field = 1; + + // Specifies that a match will be performed on the value of a field in the thrift body. + // If set, the whole http body will be buffered to extract the field value, which + // may have performance implications. + // + // It's a thrift over http version of + // :ref:`field_selector`. + // + // See also `payload-to-metadata `_ + // for more reference. + // + // Example: + // + // .. code-block:: yaml + // + // method_name: foo + // field_selector: + // name: info + // id: 2 + // child: + // name: version + // id: 1 + // + // The above yaml will match on value of ``info.version`` in the below thrift schema as input of + // :ref:`on_present` or + // :ref:`on_missing` + // while we are processing ``foo`` method. This rule won't be applied to ``bar`` method. + // + // .. code-block:: thrift + // + // struct Info { + // 1: required string version; + // } + // service Server { + // bool foo(1: i32 id, 2: Info info); + // bool bar(1: i32 id, 2: Info info); + // } + // + FieldSelector field_selector = 2 [(xds.annotations.v3.field_status).work_in_progress = true]; + + // If specified, :ref:`field_selector` + // will be used to extract the field value *only* on the thrift message with method name. + string method_name = 3 [(xds.annotations.v3.field_status).work_in_progress = true]; + + // The key-value pair to set in the *filter metadata* if the field is present + // in *thrift metadata*. + // + // If the value in the KeyValuePair is non-empty, it'll be used instead + // of field value. + KeyValuePair on_present = 4; + + // The key-value pair to set in the *filter metadata* if the field is missing + // in *thrift metadata*. + // + // The value in the KeyValuePair must be set, since it'll be used in lieu + // of the missing field value. + KeyValuePair on_missing = 5; +} + +// The configuration for transforming thrift metadata into filter metadata. +// +// [#next-free-field: 7] +message ThriftToMetadata { + // The list of rules to apply to http request body to extract thrift metadata. + repeated Rule request_rules = 1; + + // The list of rules to apply to http response body to extract thrift metadata. + repeated Rule response_rules = 2; + + // Supplies the type of transport that the Thrift proxy should use. Defaults to + // :ref:`AUTO_TRANSPORT`. + network.thrift_proxy.v3.TransportType transport = 3 + [(validate.rules).enum = {defined_only: true}]; + + // Supplies the type of protocol that the Thrift proxy should use. Defaults to + // :ref:`AUTO_PROTOCOL`. + // Note that :ref:`TWITTER` is + // not supported due to deprecation in envoy. + network.thrift_proxy.v3.ProtocolType protocol = 4 [(validate.rules).enum = {defined_only: true}]; + + // Allowed content-type for thrift payload to filter metadata transformation. + // Default to ``{"application/x-thrift"}``. + // + // Set ``allow_empty_content_type`` if empty/missing content-type header + // is allowed. + repeated string allow_content_types = 5 + [(validate.rules).repeated = {items {string {min_len: 1}}}]; + + // Allowed empty content-type for thrift payload to filter metadata transformation. + // Default to false. + bool allow_empty_content_type = 6; +} + +// Thrift to metadata configuration on a per-route basis, which overrides the global configuration for +// request rules and responses rules. +message ThriftToMetadataPerRoute { + // The list of rules to apply to http request body to extract thrift metadata. + repeated Rule request_rules = 1; + + // The list of rules to apply to http response body to extract thrift metadata. + repeated Rule response_rules = 2; +} diff --git a/api/versioning/BUILD b/api/versioning/BUILD index dc5442bbf390..35831f251fd6 100644 --- a/api/versioning/BUILD +++ b/api/versioning/BUILD @@ -153,6 +153,7 @@ proto_library( "//envoy/extensions/filters/http/set_metadata/v3:pkg", "//envoy/extensions/filters/http/stateful_session/v3:pkg", "//envoy/extensions/filters/http/tap/v3:pkg", + "//envoy/extensions/filters/http/thrift_to_metadata/v3:pkg", "//envoy/extensions/filters/http/upstream_codec/v3:pkg", "//envoy/extensions/filters/http/wasm/v3:pkg", "//envoy/extensions/filters/listener/http_inspector/v3:pkg", diff --git a/docs/root/configuration/http/http_filters/_include/thrift-to-metadata-filter.yaml b/docs/root/configuration/http/http_filters/_include/thrift-to-metadata-filter.yaml new file mode 100644 index 000000000000..f8fa4b3178ab --- /dev/null +++ b/docs/root/configuration/http/http_filters/_include/thrift-to-metadata-filter.yaml @@ -0,0 +1,99 @@ +static_resources: + listeners: + - address: + socket_address: + address: 0.0.0.0 + port_value: 80 + filter_chains: + - filters: + - name: envoy.filters.network.http_connection_manager + typed_config: + "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager + codec_type: AUTO + stat_prefix: ingress_http + route_config: + name: local_route + virtual_hosts: + - name: app + domains: + - "*" + routes: + - match: + prefix: "/" + route: + cluster: versioned-cluster + http_filters: + - name: envoy.filters.http.thrift_to_metadata + typed_config: + "@type": type.googleapis.com/envoy.extensions.filters.http.thrift_to_metadata.v3.ThriftToMetadata + request_rules: + - field: PROTOCOL + on_present: + metadata_namespace: envoy.lb + key: protocol + on_missing: + metadata_namespace: envoy.lb + key: protocol + value: "unknown" + - field: TRANSPORT + on_present: + metadata_namespace: envoy.lb + key: transport + on_missing: + metadata_namespace: envoy.lb + key: transport + value: "unknown" + response_rules: + - field: MESSAGE_TYPE + on_present: + metadata_namespace: envoy.filters.http.thrift_to_metadata + key: response_message_type + on_missing: + metadata_namespace: envoy.filters.http.thrift_to_metadata + key: response_message_type + value: "exception" + - field: REPLY_TYPE + on_present: + metadata_namespace: envoy.filters.http.thrift_to_metadata + key: response_reply_type + on_missing: + metadata_namespace: envoy.filters.http.thrift_to_metadata + key: response_reply_type + value: "error" + - name: envoy.filters.http.router + typed_config: + "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router + + clusters: + - name: versioned-cluster + type: STRICT_DNS + lb_policy: ROUND_ROBIN + lb_subset_config: + fallback_policy: ANY_ENDPOINT + subset_selectors: + - keys: + - protocol + - transport + load_assignment: + cluster_name: versioned-cluster + endpoints: + - lb_endpoints: + - endpoint: + address: + socket_address: + address: 127.0.0.1 + port_value: 8080 + metadata: + filter_metadata: + envoy.lb: + default: "true" + - lb_endpoints: + - endpoint: + address: + socket_address: + address: 127.0.0.1 + port_value: 8081 + metadata: + filter_metadata: + envoy.lb: + version: "1.0" diff --git a/docs/root/configuration/http/http_filters/http_filters.rst b/docs/root/configuration/http/http_filters/http_filters.rst index cb40dd8b0019..d9f93e0262f6 100644 --- a/docs/root/configuration/http/http_filters/http_filters.rst +++ b/docs/root/configuration/http/http_filters/http_filters.rst @@ -62,5 +62,6 @@ HTTP filters stateful_session_filter sxg_filter tap_filter + thrift_to_metadata_filter upstream_codec_filter wasm_filter diff --git a/docs/root/configuration/http/http_filters/thrift_to_metadata_filter.rst b/docs/root/configuration/http/http_filters/thrift_to_metadata_filter.rst new file mode 100644 index 000000000000..497dab730f70 --- /dev/null +++ b/docs/root/configuration/http/http_filters/thrift_to_metadata_filter.rst @@ -0,0 +1,50 @@ +.. _config_http_filters_thrift_to_metadata: + +Envoy Thrift-To-Metadata Filter +=============================== +* This filter should be configured with the type URL ``type.googleapis.com/envoy.extensions.filters.http.thrift_to_metadata.v3.ThriftToMetadata``. +* :ref:`v3 API reference ` + +The Thrift to Metadata filter serves for thrift over HTTP traffic, expecting serialized Thrift request and response bodies +in the HTTP payload. This filter is configured with rules that will be matched against Apache thrift compatible requests and +responses in HTTP payload. The filter will parse the thrift body, extract *thrift metadata* or *thrift payload*, and add them to +*dynamic filter metadata* based on the configuration of the rule. + +The *filter metadata* can then be used for load balancing decisions, consumed from logs, etc. + +A typical use case for this filter is to dynamically match a specified thrift method of requests +with rate limit. For this, thrift method name is attached to the request as dynamic filter metadata which +would then be used to match a rate limit action on filter metadata. + +Example +------- + +A sample filter configuration to route traffic to endpoints based on the presence or +absence of a version attribute could be: + +.. literalinclude:: _include/thrift-to-metadata-filter.yaml + :language: yaml + :lines: 25-55 + :lineno-start: 25 + :linenos: + :caption: :download:`thrift-to-metadata-filter.yaml <_include/thrift-to-metadata-filter.yaml>` + +Statistics +---------- + +The thrift to metadata filter outputs statistics in the *http..thrift_to_metadata.* namespace. The :ref:`stat prefix +` +comes from the owning HTTP connection manager. + +.. csv-table:: + :header: Name, Type, Description + :widths: 1, 1, 2 + + rq_success, Counter, Total requests that succeed to parse the thrift body. + rq_mismatched_content_type, Counter, Total requests that mismatch the content type + rq_no_body, Counter, Total requests without content body + rq_invalid_thrift_body, Counter, Total requests with invalid thrift body + resp_success, Counter, Total responses that succeed to parse the thrift body. + resp_mismatched_content_type, Counter, Total responses that mismatch the content type + resp_no_body, Counter, Total responses without content body + resp_invalid_thrift_body, Counter, Total responses with invalid thrift body diff --git a/source/extensions/extensions_build_config.bzl b/source/extensions/extensions_build_config.bzl index 3259d46a4b32..0c1a85fb040f 100644 --- a/source/extensions/extensions_build_config.bzl +++ b/source/extensions/extensions_build_config.bzl @@ -176,6 +176,7 @@ EXTENSIONS = { "envoy.filters.http.set_filter_state": "//source/extensions/filters/http/set_filter_state:config", "envoy.filters.http.set_metadata": "//source/extensions/filters/http/set_metadata:config", "envoy.filters.http.tap": "//source/extensions/filters/http/tap:config", + "envoy.filters.http.thrift_to_metadata": "//source/extensions/filters/http/thrift_to_metadata:config", "envoy.filters.http.wasm": "//source/extensions/filters/http/wasm:config", "envoy.filters.http.stateful_session": "//source/extensions/filters/http/stateful_session:config", "envoy.filters.http.header_mutation": "//source/extensions/filters/http/header_mutation:config", diff --git a/source/extensions/extensions_metadata.yaml b/source/extensions/extensions_metadata.yaml index fbf490fd2b76..cb9dc22929d6 100644 --- a/source/extensions/extensions_metadata.yaml +++ b/source/extensions/extensions_metadata.yaml @@ -544,6 +544,13 @@ envoy.filters.http.tap: status: alpha type_urls: - envoy.extensions.filters.http.tap.v3.Tap +envoy.filters.http.thrift_to_metadata: + categories: + - envoy.filters.http + security_posture: robust_to_untrusted_downstream + status: alpha + type_urls: + - envoy.extensions.filters.http.thrift_to_metadata.v3.ThriftToMetadata envoy.filters.http.wasm: categories: - envoy.filters.http diff --git a/source/extensions/filters/http/thrift_to_metadata/BUILD b/source/extensions/filters/http/thrift_to_metadata/BUILD new file mode 100644 index 000000000000..aeb25887da27 --- /dev/null +++ b/source/extensions/filters/http/thrift_to_metadata/BUILD @@ -0,0 +1,34 @@ +load( + "//bazel:envoy_build_system.bzl", + "envoy_cc_extension", + "envoy_cc_library", + "envoy_extension_package", +) + +licenses(["notice"]) # Apache 2 + +envoy_extension_package() + +envoy_cc_library( + name = "thrift_to_metadata_lib", + srcs = ["filter.cc"], + hdrs = ["filter.h"], + deps = [ + "//envoy/server:filter_config_interface", + "//source/common/http:header_utility_lib", + "//source/extensions/filters/http/common:pass_through_filter_lib", + "@envoy_api//envoy/extensions/filters/http/thrift_to_metadata/v3:pkg_cc_proto", + ], +) + +envoy_cc_extension( + name = "config", + srcs = ["config.cc"], + hdrs = ["config.h"], + deps = [ + ":thrift_to_metadata_lib", + "//envoy/registry", + "//source/extensions/filters/http/common:factory_base_lib", + "@envoy_api//envoy/extensions/filters/http/thrift_to_metadata/v3:pkg_cc_proto", + ], +) diff --git a/source/extensions/filters/http/thrift_to_metadata/config.cc b/source/extensions/filters/http/thrift_to_metadata/config.cc new file mode 100644 index 000000000000..ae44278dba66 --- /dev/null +++ b/source/extensions/filters/http/thrift_to_metadata/config.cc @@ -0,0 +1,36 @@ +#include "source/extensions/filters/http/thrift_to_metadata/config.h" + +#include "envoy/http/header_map.h" +#include "envoy/registry/registry.h" + +#include "source/common/protobuf/utility.h" +#include "source/extensions/filters/http/thrift_to_metadata/filter.h" + +namespace Envoy { +namespace Extensions { +namespace HttpFilters { +namespace ThriftToMetadata { + +ThriftToMetadataConfig::ThriftToMetadataConfig() + : FactoryBase("envoy.filters.http.thrift_to_metadata") {} + +Http::FilterFactoryCb ThriftToMetadataConfig::createFilterFactoryFromProtoTyped( + const envoy::extensions::filters::http::thrift_to_metadata::v3::ThriftToMetadata& proto_config, + const std::string&, Server::Configuration::FactoryContext& context) { + std::shared_ptr config = + std::make_shared(proto_config, context.scope()); + + return [config](Http::FilterChainFactoryCallbacks& callbacks) -> void { + callbacks.addStreamFilter(std::make_shared(config)); + }; +} + +/** + * Static registration for this filter. @see RegisterFactory. + */ +REGISTER_FACTORY(ThriftToMetadataConfig, Server::Configuration::NamedHttpFilterConfigFactory); + +} // namespace ThriftToMetadata +} // namespace HttpFilters +} // namespace Extensions +} // namespace Envoy diff --git a/source/extensions/filters/http/thrift_to_metadata/config.h b/source/extensions/filters/http/thrift_to_metadata/config.h new file mode 100644 index 000000000000..60b2bf7dd2bb --- /dev/null +++ b/source/extensions/filters/http/thrift_to_metadata/config.h @@ -0,0 +1,30 @@ +#pragma once + +#include + +#include "envoy/extensions/filters/http/thrift_to_metadata/v3/thrift_to_metadata.pb.h" +#include "envoy/extensions/filters/http/thrift_to_metadata/v3/thrift_to_metadata.pb.validate.h" + +#include "source/extensions/filters/http/common/factory_base.h" + +namespace Envoy { +namespace Extensions { +namespace HttpFilters { +namespace ThriftToMetadata { + +class ThriftToMetadataConfig + : public Extensions::HttpFilters::Common::FactoryBase< + envoy::extensions::filters::http::thrift_to_metadata::v3::ThriftToMetadata> { +public: + ThriftToMetadataConfig(); + +private: + Http::FilterFactoryCb createFilterFactoryFromProtoTyped( + const envoy::extensions::filters::http::thrift_to_metadata::v3::ThriftToMetadata&, + const std::string&, Server::Configuration::FactoryContext&) override; +}; + +} // namespace ThriftToMetadata +} // namespace HttpFilters +} // namespace Extensions +} // namespace Envoy diff --git a/source/extensions/filters/http/thrift_to_metadata/filter.cc b/source/extensions/filters/http/thrift_to_metadata/filter.cc new file mode 100644 index 000000000000..878f63c3fd80 --- /dev/null +++ b/source/extensions/filters/http/thrift_to_metadata/filter.cc @@ -0,0 +1,23 @@ +#include "source/extensions/filters/http/thrift_to_metadata/filter.h" + +#include "source/common/http/header_map_impl.h" +#include "source/common/http/utility.h" + +#include "absl/strings/str_cat.h" + +namespace Envoy { +namespace Extensions { +namespace HttpFilters { +namespace ThriftToMetadata { + +FilterConfig::FilterConfig( + const envoy::extensions::filters::http::thrift_to_metadata::v3::ThriftToMetadata& proto_config, + Stats::Scope& scope) { + UNREFERENCED_PARAMETER(proto_config); + UNREFERENCED_PARAMETER(scope); +} + +} // namespace ThriftToMetadata +} // namespace HttpFilters +} // namespace Extensions +} // namespace Envoy diff --git a/source/extensions/filters/http/thrift_to_metadata/filter.h b/source/extensions/filters/http/thrift_to_metadata/filter.h new file mode 100644 index 000000000000..a2223391e855 --- /dev/null +++ b/source/extensions/filters/http/thrift_to_metadata/filter.h @@ -0,0 +1,66 @@ +#pragma once + +#include +#include + +#include "envoy/extensions/filters/http/thrift_to_metadata/v3/thrift_to_metadata.pb.h" +#include "envoy/server/filter_config.h" +#include "envoy/stats/scope.h" +#include "envoy/stats/stats.h" +#include "envoy/stats/stats_macros.h" + +#include "source/common/buffer/buffer_impl.h" +#include "source/common/common/matchers.h" +#include "source/extensions/filters/http/common/pass_through_filter.h" + +#include "absl/strings/string_view.h" + +namespace Envoy { +namespace Extensions { +namespace HttpFilters { +namespace ThriftToMetadata { + +/** + * All stats for the Thrift to Metadata filter. @see stats_macros.h + */ +#define ALL_THRIFT_TO_METADATA_FILTER_STATS(COUNTER) \ + COUNTER(success) \ + COUNTER(mismatched_content_type) \ + COUNTER(no_body) \ + COUNTER(invalid_thrift_body) + +/** + * Wrapper struct for Thrift to Metadata filter stats. @see stats_macros.h + */ +struct ThriftToMetadataStats { + ALL_THRIFT_TO_METADATA_FILTER_STATS(GENERATE_COUNTER_STRUCT) +}; + +using ProtoRule = envoy::extensions::filters::http::thrift_to_metadata::v3::Rule; +using KeyValuePair = envoy::extensions::filters::http::thrift_to_metadata::v3::KeyValuePair; + +/** + * Configuration for the Thrift to Metadata filter. + */ +class FilterConfig { +public: + FilterConfig(const envoy::extensions::filters::http::thrift_to_metadata::v3::ThriftToMetadata& + proto_config, + Stats::Scope& scope); +}; + +/** + * HTTP Thrift to Metadata Filter. + */ +class Filter : public Http::PassThroughFilter, Logger::Loggable { +public: + Filter(std::shared_ptr config) : config_(config){}; + +private: + std::shared_ptr config_; +}; + +} // namespace ThriftToMetadata +} // namespace HttpFilters +} // namespace Extensions +} // namespace Envoy diff --git a/test/extensions/filters/http/thrift_to_metadata/BUILD b/test/extensions/filters/http/thrift_to_metadata/BUILD new file mode 100644 index 000000000000..df3643ba5086 --- /dev/null +++ b/test/extensions/filters/http/thrift_to_metadata/BUILD @@ -0,0 +1,34 @@ +load( + "//bazel:envoy_build_system.bzl", + "envoy_package", +) +load( + "//test/extensions:extensions_build_system.bzl", + "envoy_extension_cc_test", +) + +licenses(["notice"]) # Apache 2 + +envoy_package() + +envoy_extension_cc_test( + name = "filter_test", + srcs = ["filter_test.cc"], + extension_names = ["envoy.filters.http.thrift_to_metadata"], + deps = [ + "//source/extensions/filters/http/thrift_to_metadata:thrift_to_metadata_lib", + "//test/common/stream_info:test_util", + "//test/mocks/server:server_mocks", + "//test/mocks/upstream:upstream_mocks", + ], +) + +envoy_extension_cc_test( + name = "config_test", + srcs = ["config_test.cc"], + extension_names = ["envoy.filters.http.thrift_to_metadata"], + deps = [ + "//source/extensions/filters/http/thrift_to_metadata:config", + "//test/mocks/server:server_mocks", + ], +) diff --git a/test/extensions/filters/http/thrift_to_metadata/config_test.cc b/test/extensions/filters/http/thrift_to_metadata/config_test.cc new file mode 100644 index 000000000000..caf9bd83d974 --- /dev/null +++ b/test/extensions/filters/http/thrift_to_metadata/config_test.cc @@ -0,0 +1,66 @@ +#include "source/extensions/filters/http/thrift_to_metadata/config.h" + +#include "test/mocks/server/mocks.h" + +#include "gmock/gmock.h" +#include "gtest/gtest.h" + +namespace Envoy { +namespace Extensions { +namespace HttpFilters { +namespace ThriftToMetadata { + +TEST(Factory, Basic) { + const std::string yaml = R"( +request_rules: +- field: PROTOCOL + on_present: + metadata_namespace: envoy.lb + key: protocol + on_missing: + metadata_namespace: envoy.lb + key: protocol + value: "unknown" +- field: TRANSPORT + on_present: + metadata_namespace: envoy.lb + key: transport + on_missing: + metadata_namespace: envoy.lb + key: transport + value: "unknown" +response_rules: +- field: MESSAGE_TYPE + on_present: + metadata_namespace: envoy.filters.http.thrift_to_metadata + key: response_message_type + on_missing: + metadata_namespace: envoy.filters.http.thrift_to_metadata + key: response_message_type + value: "exception" +- field: REPLY_TYPE + on_present: + metadata_namespace: envoy.filters.http.thrift_to_metadata + key: response_reply_type + on_missing: + metadata_namespace: envoy.filters.http.thrift_to_metadata + key: response_reply_type + value: "error" + )"; + + ThriftToMetadataConfig factory; + ProtobufTypes::MessagePtr proto_config = factory.createEmptyRouteConfigProto(); + TestUtility::loadFromYaml(yaml, *proto_config); + + NiceMock context; + + auto callback = factory.createFilterFactoryFromProto(*proto_config, "stats", context).value(); + Http::MockFilterChainFactoryCallbacks filter_callback; + EXPECT_CALL(filter_callback, addStreamFilter(_)); + callback(filter_callback); +} + +} // namespace ThriftToMetadata +} // namespace HttpFilters +} // namespace Extensions +} // namespace Envoy diff --git a/test/extensions/filters/http/thrift_to_metadata/filter_test.cc b/test/extensions/filters/http/thrift_to_metadata/filter_test.cc new file mode 100644 index 000000000000..c7e7aa083648 --- /dev/null +++ b/test/extensions/filters/http/thrift_to_metadata/filter_test.cc @@ -0,0 +1,87 @@ +#include + +#include "envoy/http/header_map.h" + +#include "source/extensions/filters/http/thrift_to_metadata/filter.h" + +#include "test/common/stream_info/test_util.h" +#include "test/mocks/http/mocks.h" +#include "test/mocks/server/mocks.h" +#include "test/mocks/stats/mocks.h" +#include "test/mocks/stream_info/mocks.h" +#include "test/test_common/utility.h" + +#include "gmock/gmock.h" +#include "gtest/gtest.h" + +namespace Envoy { +namespace Extensions { +namespace HttpFilters { +namespace ThriftToMetadata { + +class FilterTest : public testing::Test { +public: + FilterTest() = default; + + const std::string config_yaml_ = R"EOF( +request_rules: +- field: PROTOCOL + on_present: + metadata_namespace: envoy.lb + key: protocol + on_missing: + metadata_namespace: envoy.lb + key: protocol + value: "unknown" +- field: TRANSPORT + on_present: + metadata_namespace: envoy.lb + key: transport + on_missing: + metadata_namespace: envoy.lb + key: transport + value: "unknown" +response_rules: +- field: MESSAGE_TYPE + on_present: + metadata_namespace: envoy.filters.http.thrift_to_metadata + key: response_message_type + on_missing: + metadata_namespace: envoy.filters.http.thrift_to_metadata + key: response_message_type + value: "exception" +- field: REPLY_TYPE + on_present: + metadata_namespace: envoy.filters.http.thrift_to_metadata + key: response_reply_type + on_missing: + metadata_namespace: envoy.filters.http.thrift_to_metadata + key: response_reply_type + value: "error" +)EOF"; + + void initializeFilter(const std::string& yaml) { + envoy::extensions::filters::http::thrift_to_metadata::v3::ThriftToMetadata config; + TestUtility::loadFromYaml(yaml, config); + config_ = std::make_shared(config, *scope_.rootScope()); + filter_ = std::make_shared(config_); + filter_->setDecoderFilterCallbacks(decoder_callbacks_); + filter_->setEncoderFilterCallbacks(encoder_callbacks_); + } + + NiceMock scope_; + NiceMock decoder_callbacks_; + NiceMock encoder_callbacks_; + std::shared_ptr config_; + std::shared_ptr filter_; +}; + +TEST_F(FilterTest, Basic) { + initializeFilter(config_yaml_); + EXPECT_TRUE(true); +} + +} // namespace ThriftToMetadata +} // namespace HttpFilters +} // namespace Extensions +} // namespace Envoy