### Configure HTTP filter chain Source: https://github.com/envoyproxy/envoy-filter-example/blob/main/http-filter-example/README.md Example YAML configuration for adding the custom filter to the Envoy filter chain. ```yaml http_filters: - name: sample # before envoy.router because order matters! typed_config: "@type": type.googleapis.com/sample.Decoder key: via val: sample-filter - name: envoy.router typed_config: {} ``` -------------------------------- ### Build Envoy static binary Source: https://github.com/envoyproxy/envoy-filter-example/blob/main/http-filter-example/README.md Commands to initialize submodules and build the Envoy binary using Bazel. ```bash git submodule update --init ``` ```bash bazel build //http-filter-example:envoy ``` -------------------------------- ### Build Envoy with Custom Filters using Bazel Source: https://context7.com/envoyproxy/envoy-filter-example/llms.txt Builds the Envoy static binary with custom filters linked in. Ensure submodules are initialized before building. ```bash # Initialize submodules to get the Envoy source git submodule update --init # Build the Envoy binary with echo2 filter bazel build //:envoy # Build the HTTP filter example bazel build //http-filter-example:envoy ``` -------------------------------- ### Run integration tests Source: https://github.com/envoyproxy/envoy-filter-example/blob/main/http-filter-example/README.md Command to execute the integration test suite for the sample filter. ```bash bazel test //http-filter-example:http_filter_integration_test ``` -------------------------------- ### Implement HTTP filter logic Source: https://context7.com/envoyproxy/envoy-filter-example/llms.txt C++ implementation file for the HTTP decoder filter, demonstrating header injection in decodeHeaders. ```cpp // http_filter.cc - HTTP filter implementation #include #include "http_filter.h" #include "envoy/server/filter_config.h" namespace Envoy { namespace Http { HttpSampleDecoderFilterConfig::HttpSampleDecoderFilterConfig( const sample::Decoder& proto_config) : key_(proto_config.key()), val_(proto_config.val()) {} HttpSampleDecoderFilter::HttpSampleDecoderFilter(HttpSampleDecoderFilterConfigSharedPtr config) : config_(config) {} HttpSampleDecoderFilter::~HttpSampleDecoderFilter() {} void HttpSampleDecoderFilter::onDestroy() {} const LowerCaseString HttpSampleDecoderFilter::headerKey() const { return LowerCaseString(config_->key()); } const std::string HttpSampleDecoderFilter::headerValue() const { return config_->val(); } // Add custom header to incoming requests FilterHeadersStatus HttpSampleDecoderFilter::decodeHeaders(RequestHeaderMap& headers, bool) { headers.addCopy(headerKey(), headerValue()); return FilterHeadersStatus::Continue; } FilterDataStatus HttpSampleDecoderFilter::decodeData(Buffer::Instance&, bool) { return FilterDataStatus::Continue; } void HttpSampleDecoderFilter::setDecoderFilterCallbacks(StreamDecoderFilterCallbacks& callbacks) { decoder_callbacks_ = &callbacks; } } // namespace Http } // namespace Envoy ``` -------------------------------- ### Execute Integration Tests with Bazel Source: https://context7.com/envoyproxy/envoy-filter-example/llms.txt Commands to run specific filter integration tests or the full Envoy test suite. ```bash # Run echo2 network filter integration test bazel test //:echo2_integration_test # Run HTTP filter integration test bazel test //http-filter-example:http_filter_integration_test # Run all standard Envoy tests bazel test @envoy//test/... ``` -------------------------------- ### Implement Echo2 Integration Test in C++ Source: https://context7.com/envoyproxy/envoy-filter-example/llms.txt Uses the BaseIntegrationTest class to verify network filter behavior by echoing data back to a client. ```cpp // echo2_integration_test.cc - Integration test for echo2 filter #include "test/integration/integration.h" #include "test/integration/utility.h" namespace Envoy { class Echo2IntegrationTest : public BaseIntegrationTest, public testing::TestWithParam { std::string echoConfig() { return TestEnvironment::readFileToStringForTest( TestEnvironment::runfilesPath("echo2_server.yaml", "envoy_filter_example")); } public: Echo2IntegrationTest() : BaseIntegrationTest(GetParam(), echoConfig()) {} void SetUp() override { BaseIntegrationTest::initialize(); } void TearDown() override { test_server_.reset(); fake_upstreams_.clear(); } }; INSTANTIATE_TEST_SUITE_P(IpVersions, Echo2IntegrationTest, testing::ValuesIn(TestEnvironment::getIpVersionsForTest())); TEST_P(Echo2IntegrationTest, Echo) { std::string response; auto connection = createConnectionDriver( lookupPort("listener_0"), "hello", [&](Network::ClientConnection& conn, const Buffer::Instance& data) -> void { response.append(data.toString()); conn.close(Network::ConnectionCloseType::FlushWrite); }); connection->run(); EXPECT_EQ("hello", response); // Verify echo behavior } } // namespace Envoy ``` -------------------------------- ### Configure Bazel Build Targets Source: https://context7.com/envoyproxy/envoy-filter-example/llms.txt Defines build targets for custom Envoy filters using standard Envoy build system macros. ```python # BUILD - Root level build file package(default_visibility = ["//visibility:public"]) load( "@envoy//bazel:envoy_build_system.bzl", "envoy_cc_binary", "envoy_cc_library", "envoy_cc_test", ) # Custom Envoy binary with echo2 filter envoy_cc_binary( name = "envoy", repository = "@envoy", deps = [ ":echo2_config", "@envoy//source/exe:envoy_main_entry_lib", ], ) # Echo2 filter library envoy_cc_library( name = "echo2_lib", srcs = ["echo2.cc"], hdrs = ["echo2.h"], repository = "@envoy", deps = [ "@envoy//envoy/buffer:buffer_interface", "@envoy//envoy/network:connection_interface", "@envoy//envoy//network:filter_interface", "@envoy//source/common/common:assert_lib", "@envoy//source/common/common:logger_lib", ], ) # Echo2 config factory envoy_cc_library( name = "echo2_config", srcs = ["echo2_config.cc"], repository = "@envoy", deps = [ ":echo2_lib", "@envoy//envoy/network:filter_interface", "@envoy//envoy/registry:registry", "@envoy//envoy/server:filter_config_interface", ], ) # Integration test for echo2 envoy_cc_test( name = "echo2_integration_test", srcs = ["echo2_integration_test.cc"], data = ["echo2_server.yaml"], repository = "@envoy", deps = [ ":echo2_config", "@envoy//test/integration:integration_lib", ], ) ``` -------------------------------- ### Implement HTTP filter header Source: https://context7.com/envoyproxy/envoy-filter-example/llms.txt C++ header file defining the configuration class and the filter class inheriting from PassThroughDecoderFilter. ```cpp // http_filter.h - HTTP filter header #pragma once #include #include "source/extensions/filters/http/common/pass_through_filter.h" #include "http-filter-example/http_filter.pb.h" namespace Envoy { namespace Http { class HttpSampleDecoderFilterConfig { public: HttpSampleDecoderFilterConfig(const sample::Decoder& proto_config); const std::string& key() const { return key_; } const std::string& val() const { return val_; } private: const std::string key_; const std::string val_; }; using HttpSampleDecoderFilterConfigSharedPtr = std::shared_ptr; class HttpSampleDecoderFilter : public PassThroughDecoderFilter { public: HttpSampleDecoderFilter(HttpSampleDecoderFilterConfigSharedPtr); ~HttpSampleDecoderFilter(); void onDestroy() override; FilterHeadersStatus decodeHeaders(RequestHeaderMap&, bool) override; FilterDataStatus decodeData(Buffer::Instance&, bool) override; void setDecoderFilterCallbacks(StreamDecoderFilterCallbacks&) override; private: const HttpSampleDecoderFilterConfigSharedPtr config_; StreamDecoderFilterCallbacks* decoder_callbacks_; const LowerCaseString headerKey() const; const std::string headerValue() const; }; } // namespace Http } // namespace Envoy ``` -------------------------------- ### Configure echo2 filter in YAML Source: https://context7.com/envoyproxy/envoy-filter-example/llms.txt Defines the Envoy static resources and listener configuration for the echo2 filter. ```yaml admin: access_log_path: /dev/null address: socket_address: address: 127.0.0.1 port_value: 0 static_resources: clusters: name: cluster_0 connect_timeout: 0.25s load_assignment: cluster_name: cluster_0 endpoints: - lb_endpoints: - endpoint: address: socket_address: address: 127.0.0.1 port_value: 0 listeners: name: listener_0 address: socket_address: address: 127.0.0.1 port_value: 0 filter_chains: - filters: - name: echo2 typed_config: "@type": type.googleapis.com/google.protobuf.Struct ``` -------------------------------- ### Register HTTP Filter Factory in C++ Source: https://context7.com/envoyproxy/envoy-filter-example/llms.txt Implements the NamedHttpFilterConfigFactory to register a custom filter with the Envoy server. ```cpp // http_filter_config.cc - HTTP filter factory registration #include #include "envoy/registry/registry.h" #include "envoy/server/filter_config.h" #include "http-filter-example/http_filter.pb.h" #include "http-filter-example/http_filter.pb.validate.h" #include "http_filter.h" namespace Envoy { namespace Server { namespace Configuration { class HttpSampleDecoderFilterConfigFactory : public NamedHttpFilterConfigFactory { public: Http::FilterFactoryCb createFilterFactoryFromProto(const Protobuf::Message& proto_config, const std::string&, FactoryContext& context) override { return createFilter(Envoy::MessageUtil::downcastAndValidate( proto_config, context.messageValidationVisitor()), context); } ProtobufTypes::MessagePtr createEmptyConfigProto() override { return ProtobufTypes::MessagePtr{new sample::Decoder()}; } std::string name() const override { return "sample"; } private: Http::FilterFactoryCb createFilter(const sample::Decoder& proto_config, FactoryContext&) { Http::HttpSampleDecoderFilterConfigSharedPtr config = std::make_shared( Http::HttpSampleDecoderFilterConfig(proto_config)); return [config](Http::FilterChainFactoryCallbacks& callbacks) -> void { auto filter = new Http::HttpSampleDecoderFilter(config); callbacks.addStreamDecoderFilter(Http::StreamDecoderFilterSharedPtr{filter}); }; } }; // Static registration for the sample filter static Registry::RegisterFactory register_; } // namespace Configuration } // namespace Server } // namespace Envoy ``` -------------------------------- ### Register Echo2 Network Filter Source: https://context7.com/envoyproxy/envoy-filter-example/llms.txt Registers the echo2 network filter with Envoy's filter factory system using static initialization. This filter is terminal. ```cpp // echo2_config.cc - Filter factory registration #include #include "echo2.h" #include "envoy/registry/registry.h" #include "envoy/server/filter_config.h" namespace Envoy { namespace Server { namespace Configuration { class Echo2ConfigFactory : public NamedNetworkFilterConfigFactory { public: // Create filter instance from protobuf config Network::FilterFactoryCb createFilterFactoryFromProto(const Protobuf::Message&, FactoryContext&) override { return [](Network::FilterManager& filter_manager) -> void { filter_manager.addReadFilter(Network::ReadFilterSharedPtr{new Filter::Echo2()}); }; } // Return empty config proto (filter has no configuration) ProtobufTypes::MessagePtr createEmptyConfigProto() override { return ProtobufTypes::MessagePtr{new Envoy::ProtobufWkt::Struct()}; } // Filter name used in Envoy configuration std::string name() const override { return "echo2"; } // This filter terminates the filter chain bool isTerminalFilterByProto(const Protobuf::Message&, ServerFactoryContext&) override { return true; } }; // Static registration - filter is registered at startup static Registry::RegisterFactory registered_; } // namespace Configuration } // namespace Server } // namespace Envoy ``` -------------------------------- ### Configure HTTP Filter Chain in YAML Source: https://context7.com/envoyproxy/envoy-filter-example/llms.txt Defines the filter order in the Envoy HTTP filter chain, ensuring the custom filter precedes the router. ```yaml # Example Envoy HTTP filter chain configuration http_filters: - name: sample # Must come before envoy.router - order matters! typed_config: "@type": type.googleapis.com/sample.Decoder key: via val: sample-filter - name: envoy.router typed_config: {} ``` -------------------------------- ### Define HTTP filter configuration schema Source: https://context7.com/envoyproxy/envoy-filter-example/llms.txt Protobuf message definition for the HTTP decoder filter configuration. ```protobuf // http_filter.proto - Filter configuration schema syntax = "proto3"; package sample; import "validate/validate.proto"; message Decoder { string key = 1 [(validate.rules).string.min_bytes = 1]; string val = 2 [(validate.rules).string.min_bytes = 1]; } ``` -------------------------------- ### Test HTTP Filter Integration Source: https://context7.com/envoyproxy/envoy-filter-example/llms.txt Verifies that a custom HTTP filter correctly modifies request headers during an integration test. ```cpp // http_filter_integration_test.cc - Integration test for HTTP filter #include "test/integration/http_integration.h" namespace Envoy { class HttpFilterSampleIntegrationTest : public HttpIntegrationTest, public testing::TestWithParam { public: HttpFilterSampleIntegrationTest() : HttpIntegrationTest(Http::CodecClient::Type::HTTP1, GetParam()) {} void SetUp() override { initialize(); } void initialize() override { // Prepend sample filter to HTTP filter chain config_helper_.prependFilter( "{ name: sample, typed_config: { \"@type\": type.googleapis.com/sample.Decoder, key: via, " "val: sample-filter } }"); HttpIntegrationTest::initialize(); } }; INSTANTIATE_TEST_SUITE_P(IpVersions, HttpFilterSampleIntegrationTest, testing::ValuesIn(TestEnvironment::getIpVersionsForTest())); TEST_P(HttpFilterSampleIntegrationTest, Test1) { Http::TestRequestHeaderMapImpl headers{ {":method", "GET"}, {":path", "/"}, {":authority", "host"}}; Http::TestRequestHeaderMapImpl response_headers{{":status", "200"}}; IntegrationCodecClientPtr codec_client; FakeHttpConnectionPtr fake_upstream_connection; FakeStreamPtr request_stream; codec_client = makeHttpConnection(lookupPort("http")); auto response = codec_client->makeHeaderOnlyRequest(headers); ASSERT_TRUE(fake_upstreams_[0]->waitForHttpConnection(*dispatcher_, fake_upstream_connection)); ASSERT_TRUE(fake_upstream_connection->waitForNewStream(*dispatcher_, request_stream)); ASSERT_TRUE(request_stream->waitForEndStream(*dispatcher_)); request_stream->encodeHeaders(response_headers, true); ASSERT_TRUE(response->waitForEndStream()); // Verify the sample filter added the \"via\" header EXPECT_EQ( "sample-filter", request_stream->headers().get(Http::LowerCaseString("via"))[0]->value().getStringView()); codec_client->close(); } } // namespace Envoy ``` -------------------------------- ### Echo2 Network Filter Implementation Source: https://context7.com/envoyproxy/envoy-filter-example/llms.txt Implements the Echo2 network filter's onData method to echo received data back to the client. It stops further filter iteration after echoing. ```cpp // echo2.cc - Network filter implementation #include "echo2.h" #include "envoy/buffer/buffer.h" #include "envoy/network/connection.h" #include "source/common/common/assert.h" namespace Envoy { namespace Filter { Network::FilterStatus Echo2::onData(Buffer::Instance& data, bool) { ENVOY_CONN_LOG(trace, "echo: got {} bytes", read_callbacks_->connection(), data.length()); // Echo the received data back to the client read_callbacks_->connection().write(data, false); return Network::FilterStatus::StopIteration; } } // namespace Filter } // namespace Envoy ``` -------------------------------- ### Echo2 Network Filter Header Source: https://context7.com/envoyproxy/envoy-filter-example/llms.txt Defines the Echo2 network filter, implementing the Network::ReadFilter interface to echo back received data. It requires initialization of read filter callbacks. ```cpp // echo2.h - Network filter header #pragma once #include "envoy/network/filter.h" #include "source/common/common/logger.h" namespace Envoy { namespace Filter { class Echo2 : public Network::ReadFilter, Logger::Loggable { public: // Called when data is received on the connection Network::FilterStatus onData(Buffer::Instance& data, bool end_stream) override; // Called when a new connection is established Network::FilterStatus onNewConnection() override { return Network::FilterStatus::Continue; } // Initialize filter callbacks void initializeReadFilterCallbacks(Network::ReadFilterCallbacks& callbacks) override { read_callbacks_ = &callbacks; } private: Network::ReadFilterCallbacks* read_callbacks_{}; }; } // namespace Filter } // namespace Envoy ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.