diff --git a/source/common/quic/envoy_quic_client_connection.cc b/source/common/quic/envoy_quic_client_connection.cc index 411cfcece015..1d09d97a02ab 100644 --- a/source/common/quic/envoy_quic_client_connection.cc +++ b/source/common/quic/envoy_quic_client_connection.cc @@ -64,6 +64,12 @@ EnvoyQuicClientConnection::EnvoyQuicClientConnection( prefer_gro_(prefer_gro), disallow_mmsg_(Runtime::runtimeFeatureEnabled( "envoy.reloadable_features.disallow_quic_client_udp_mmsg")) {} +EnvoyQuicClientConnection::~EnvoyQuicClientConnection() { + if (poll_timer_) { + poll_timer_->disableTimer(); + } +} + void EnvoyQuicClientConnection::processPacket( Network::Address::InstanceConstSharedPtr local_address, Network::Address::InstanceConstSharedPtr peer_address, Buffer::InstancePtr buffer, @@ -131,6 +137,24 @@ void EnvoyQuicClientConnection::setUpConnectionSocket(Network::ConnectionSocket& if (!connection_socket.isOpen()) { CloseConnection(quic::QUIC_CONNECTION_CANCELLED, "Fail to set up connection socket.", quic::ConnectionCloseBehavior::SILENT_CLOSE); + } else { + int poll_time = 0; + if (Runtime::runtimeFeatureEnabled("envoy.reloadable_features.quic_client_3ms_poll")) { + poll_time = 3; + } else if (Runtime::runtimeFeatureEnabled("envoy.reloadable_features.quic_client_5ms_poll")) { + poll_time = 5; + } + if (poll_time) { + if (!poll_timer_) { + poll_timer_ = dispatcher_.createTimer([this, poll_time]() { + if (connected() && connectionSocket()) { + connectionSocket()->ioHandle().activateFileEvents(Event::FileReadyType::Read); + poll_timer_->enableTimer(std::chrono::milliseconds(poll_time)); + } + }); + } + poll_timer_->enableTimer(std::chrono::milliseconds(poll_time)); + } } } diff --git a/source/common/quic/envoy_quic_client_connection.h b/source/common/quic/envoy_quic_client_connection.h index 8530386f6483..2993010e1f17 100644 --- a/source/common/quic/envoy_quic_client_connection.h +++ b/source/common/quic/envoy_quic_client_connection.h @@ -71,6 +71,8 @@ class EnvoyQuicClientConnection : public quic::QuicConnection, Network::ConnectionSocketPtr&& connection_socket, quic::ConnectionIdGeneratorInterface& generator, bool prefer_gro); + virtual ~EnvoyQuicClientConnection(); + // Network::UdpPacketProcessor void processPacket(Network::Address::InstanceConstSharedPtr local_address, Network::Address::InstanceConstSharedPtr peer_address, @@ -144,6 +146,7 @@ class EnvoyQuicClientConnection : public quic::QuicConnection, void probeWithNewPort(const quic::QuicSocketAddress& peer_address, quic::PathValidationReason reason); + Event::TimerPtr poll_timer_; OptRef delegate_; uint32_t packets_dropped_{0}; Event::Dispatcher& dispatcher_; diff --git a/source/common/runtime/runtime_features.cc b/source/common/runtime/runtime_features.cc index 25cd64d30ded..87b7e67c93f5 100644 --- a/source/common/runtime/runtime_features.cc +++ b/source/common/runtime/runtime_features.cc @@ -153,6 +153,9 @@ FALSE_RUNTIME_GUARD(envoy_restart_features_xds_failover_support); FALSE_RUNTIME_GUARD(envoy_reloadable_features_dns_cache_set_ip_version_to_remove); // TODO(alyssawilk): evaluate and make this a config knob or remove. FALSE_RUNTIME_GUARD(envoy_reloadable_features_reset_brokenness_on_nework_change); +// TODO(abeyad): Remove the polling timer flags once the Envoy Mobile experiment is finished. +FALSE_RUNTIME_GUARD(envoy_reloadable_features_quic_client_3ms_poll); +FALSE_RUNTIME_GUARD(envoy_reloadable_features_quic_client_5ms_poll); // A flag to set the maximum TLS version for google_grpc client to TLS1.2, when needed for // compliance restrictions. diff --git a/test/integration/protocol_integration_test.cc b/test/integration/protocol_integration_test.cc index 261ddd3c430e..c85231d1960b 100644 --- a/test/integration/protocol_integration_test.cc +++ b/test/integration/protocol_integration_test.cc @@ -1463,6 +1463,36 @@ TEST_P(DownstreamProtocolIntegrationTest, HittingDecoderFilterLimitNoEndStream) } } +TEST_P(ProtocolIntegrationTest, TestLargeResposneBody) { + config_helper_.addRuntimeOverride("envoy.reloadable_features.quic_client_3ms_poll", "true"); + initialize(); + + codec_client_ = makeHttpConnection(lookupPort("http")); + auto response = codec_client_->makeHeaderOnlyRequest(default_request_headers_); + + waitForNextUpstreamRequest(); + upstream_request_->encodeHeaders(default_response_headers_, false); + upstream_request_->encodeData(1024 * 200, true); + + ASSERT_TRUE(response->waitForEndStream()); + EXPECT_TRUE(response->complete()); +} + +TEST_P(ProtocolIntegrationTest, TestLargeResposneBodyFive) { + config_helper_.addRuntimeOverride("envoy.reloadable_features.quic_client_5ms_poll", "true"); + initialize(); + + codec_client_ = makeHttpConnection(lookupPort("http")); + auto response = codec_client_->makeHeaderOnlyRequest(default_request_headers_); + + waitForNextUpstreamRequest(); + upstream_request_->encodeHeaders(default_response_headers_, false); + upstream_request_->encodeData(1024 * 200, true); + + ASSERT_TRUE(response->waitForEndStream()); + EXPECT_TRUE(response->complete()); +} + // Test hitting the encoder buffer filter with too many response bytes to buffer. Given the request // headers are sent on early, the stream/connection will be reset. TEST_P(ProtocolIntegrationTest, HittingEncoderFilterLimit) {