@@ -351,6 +351,8 @@ class UdpTunnelingIntegrationTest : public HttpProtocolIntegrationTest {
351351 absl::optional<BufferOptions> buffer_options_;
352352 absl::optional<std::string> idle_timeout_;
353353 std::string session_access_log_config_ = " " ;
354+ bool propagate_response_headers_ = false ;
355+ bool propagate_response_trailers_ = false ;
354356 };
355357
356358 void setup (const TestConfig& config) {
@@ -379,9 +381,12 @@ name: udp_proxy
379381 default_target_port: {}
380382 retry_options:
381383 max_connect_attempts: {}
384+ propagate_response_headers: {}
385+ propagate_response_trailers: {}
382386)EOF" ,
383387 config.proxy_host_ , config.target_host_ , config.default_target_port_ ,
384- config.max_connect_attempts_ );
388+ config.max_connect_attempts_ , config.propagate_response_headers_ ,
389+ config.propagate_response_trailers_ );
385390
386391 if (config.buffer_options_ .has_value ()) {
387392 filter_config += fmt::format (R"EOF(
@@ -739,6 +744,141 @@ TEST_P(UdpTunnelingIntegrationTest, ConnectionAttemptRetry) {
739744 EXPECT_THAT (waitForAccessLog (access_log_filename), testing::HasSubstr (" 2" ));
740745}
741746
747+ TEST_P (UdpTunnelingIntegrationTest, PropagateValidResponseHeaders) {
748+ const std::string access_log_filename =
749+ TestEnvironment::temporaryPath (TestUtility::uniqueFilename ());
750+
751+ const std::string session_access_log_config = fmt::format (R"EOF(
752+ access_log:
753+ - name: envoy.access_loggers.file
754+ typed_config:
755+ '@type': type.googleapis.com/envoy.extensions.access_loggers.file.v3.FileAccessLog
756+ path: {}
757+ log_format:
758+ text_format_source:
759+ inline_string: "%FILTER_STATE(envoy.udp_proxy.propagate_response_headers:TYPED)%\n"
760+ )EOF" ,
761+ access_log_filename);
762+
763+ const TestConfig config{" host.com" ,
764+ " target.com" ,
765+ 1 ,
766+ 30 ,
767+ false ,
768+ " " ,
769+ BufferOptions{1 , 30 },
770+ absl::nullopt ,
771+ session_access_log_config,
772+ true ,
773+ false };
774+ setup (config);
775+
776+ const std::string datagram = " hello" ;
777+ establishConnection (datagram);
778+
779+ // Wait for buffered datagram.
780+ ASSERT_TRUE (upstream_request_->waitForData (*dispatcher_, expectedCapsules ({datagram})));
781+
782+ sendCapsuleDownstream (" response" , true );
783+ test_server_->waitForGaugeEq (" udp.foo.downstream_sess_active" , 0 );
784+
785+ // Verify response header value is in the access log.
786+ EXPECT_THAT (waitForAccessLog (access_log_filename), testing::HasSubstr (" capsule-protocol" ));
787+ }
788+
789+ TEST_P (UdpTunnelingIntegrationTest, PropagateInvalidResponseHeaders) {
790+ const std::string access_log_filename =
791+ TestEnvironment::temporaryPath (TestUtility::uniqueFilename ());
792+
793+ const std::string session_access_log_config = fmt::format (R"EOF(
794+ access_log:
795+ - name: envoy.access_loggers.file
796+ typed_config:
797+ '@type': type.googleapis.com/envoy.extensions.access_loggers.file.v3.FileAccessLog
798+ path: {}
799+ log_format:
800+ text_format_source:
801+ inline_string: "%FILTER_STATE(envoy.udp_proxy.propagate_response_headers:TYPED)%\n"
802+ )EOF" ,
803+ access_log_filename);
804+
805+ const TestConfig config{" host.com" ,
806+ " target.com" ,
807+ 1 ,
808+ 30 ,
809+ false ,
810+ " " ,
811+ BufferOptions{1 , 30 },
812+ absl::nullopt ,
813+ session_access_log_config,
814+ true ,
815+ false };
816+ setup (config);
817+
818+ client_->write (" hello" , *listener_address_);
819+ ASSERT_TRUE (fake_upstreams_[0 ]->waitForHttpConnection (*dispatcher_, fake_upstream_connection_));
820+ ASSERT_TRUE (fake_upstream_connection_->waitForNewStream (*dispatcher_, upstream_request_));
821+ ASSERT_TRUE (upstream_request_->waitForHeadersComplete ());
822+ expectRequestHeaders (upstream_request_->headers ());
823+
824+ Http::TestResponseHeaderMapImpl response_headers{{" :status" , " 404" }};
825+ upstream_request_->encodeHeaders (response_headers, true );
826+
827+ test_server_->waitForCounterEq (" cluster.cluster_0.upstream_cx_connect_attempts_exceeded" , 1 );
828+ test_server_->waitForCounterEq (" cluster.cluster_0.udp.sess_tunnel_failure" , 1 );
829+ test_server_->waitForCounterEq (" cluster.cluster_0.udp.sess_tunnel_success" , 0 );
830+ test_server_->waitForGaugeEq (" udp.foo.downstream_sess_active" , 0 );
831+
832+ // Verify response header value is in the access log.
833+ EXPECT_THAT (waitForAccessLog (access_log_filename), testing::HasSubstr (" 404" ));
834+ }
835+
836+ TEST_P (UdpTunnelingIntegrationTest, PropagateResponseTrailers) {
837+ const std::string access_log_filename =
838+ TestEnvironment::temporaryPath (TestUtility::uniqueFilename ());
839+
840+ const std::string session_access_log_config = fmt::format (R"EOF(
841+ access_log:
842+ - name: envoy.access_loggers.file
843+ typed_config:
844+ '@type': type.googleapis.com/envoy.extensions.access_loggers.file.v3.FileAccessLog
845+ path: {}
846+ log_format:
847+ text_format_source:
848+ inline_string: "%FILTER_STATE(envoy.udp_proxy.propagate_response_trailers:TYPED)%\n"
849+ )EOF" ,
850+ access_log_filename);
851+
852+ const TestConfig config{" host.com" ,
853+ " target.com" ,
854+ 1 ,
855+ 30 ,
856+ false ,
857+ " " ,
858+ BufferOptions{1 , 30 },
859+ absl::nullopt ,
860+ session_access_log_config,
861+ false ,
862+ true };
863+ setup (config);
864+
865+ const std::string datagram = " hello" ;
866+ establishConnection (datagram);
867+
868+ // Wait for buffered datagram.
869+ ASSERT_TRUE (upstream_request_->waitForData (*dispatcher_, expectedCapsules ({datagram})));
870+ sendCapsuleDownstream (" response" , false );
871+
872+ const std::string trailer_value = " test-trailer-value" ;
873+ Http::TestResponseTrailerMapImpl response_trailers{{" test-trailer-name" , trailer_value}};
874+ upstream_request_->encodeTrailers (response_trailers);
875+
876+ test_server_->waitForGaugeEq (" udp.foo.downstream_sess_active" , 0 );
877+
878+ // Verify response trailer value is in the access log.
879+ EXPECT_THAT (waitForAccessLog (access_log_filename), testing::HasSubstr (trailer_value));
880+ }
881+
742882INSTANTIATE_TEST_SUITE_P (IpAndHttpVersions, UdpTunnelingIntegrationTest,
743883 testing::ValuesIn (HttpProtocolIntegrationTest::getProtocolTestParams(
744884 {Http::CodecType::HTTP2}, {Http::CodecType::HTTP2})),
0 commit comments