Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions docs/root/api/starting_envoy.rst
Original file line number Diff line number Diff line change
Expand Up @@ -416,6 +416,22 @@ Specify whether sockets may attempt to bind to a specific interface, based on ne
// Swift
builder.enableInterfaceBinding(true)

~~~~~~~~~~~~~~~~~~~~~~~~~~~~
``h2ExtendKeepaliveTimeout``
~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Extend the keepalive timeout when *any* frame is received on the owning HTTP/2 connection.

This can help negate the effect of head-of-line (HOL) blocking for slow connections.

**Example**::

// Kotlin
builder.h2ExtendKeepaliveTimeout(true)

// Swift
builder.h2ExtendKeepaliveTimeout(true)

----------------------
Advanced configuration
----------------------
Expand Down
2 changes: 1 addition & 1 deletion docs/root/intro/version_history.rst
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ Bugfixes:

Features:

- None
- api: add option to extend the keepalive timeout when any frame is received on the owning HTTP/2 connection. (:issue:`#2229 <2229>`)

0.4.6 (April 26, 2022)
========================
Expand Down
2 changes: 1 addition & 1 deletion envoy
Submodule envoy updated 224 files
2 changes: 2 additions & 0 deletions library/common/config/config.cc
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ const std::string config_header = R"(
- &enable_interface_binding false
- &h2_connection_keepalive_idle_interval 100000s
- &h2_connection_keepalive_timeout 10s
- &h2_delay_keepalive_timeout false
- &h2_raw_domains []
- &max_connections_per_host 7
- &metadata {}
Expand Down Expand Up @@ -464,6 +465,7 @@ stats_sinks: *stats_sinks
reloadable_features:
allow_multiple_dns_addresses: *dns_multiple_addresses
override_request_timeout_by_gateway_timeout: false
http2_delay_keepalive_timeout: *h2_delay_keepalive_timeout
)"
// Needed due to warning in
// https://github.com/envoyproxy/envoy/blob/6eb7e642d33f5a55b63c367188f09819925fca34/source/server/server.cc#L546
Expand Down
2 changes: 1 addition & 1 deletion library/common/engine.cc
Original file line number Diff line number Diff line change
Expand Up @@ -304,7 +304,7 @@ void Engine::flushStats() {
void Engine::drainConnections() {
ASSERT(dispatcher_->isThreadSafe(),
"drainConnections must be called from the dispatcher's context");
server_->clusterManager().drainConnections();
server_->clusterManager().drainConnections(nullptr);
}

Upstream::ClusterManager& Engine::getClusterManager() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ public enum TrustChainVerification {
public final Boolean enableInterfaceBinding;
public final Integer h2ConnectionKeepaliveIdleIntervalMilliseconds;
public final Integer h2ConnectionKeepaliveTimeoutSeconds;
public final Boolean h2ExtendKeepaliveTimeout;
public final List<String> h2RawDomains;
public final Integer maxConnectionsPerHost;
public final List<EnvoyHTTPFilterFactory> httpPlatformFilterFactories;
Expand Down Expand Up @@ -76,6 +77,8 @@ public enum TrustChainVerification {
* @param h2ConnectionKeepaliveIdleIntervalMilliseconds rate in milliseconds seconds to send h2
* pings on stream creation.
* @param h2ConnectionKeepaliveTimeoutSeconds rate in seconds to timeout h2 pings.
* @param h2ExtendKeepaliveTimeout Extend the keepalive timeout when *any* frame is received
* on the owning HTTP/2 connection.
* @param h2RawDomains list of domains to which connections should be raw h2.
* @param maxConnectionsPerHost maximum number of connections to open to a single host.
* @param statsFlushSeconds interval at which to flush Envoy stats.
Expand All @@ -96,10 +99,11 @@ public EnvoyConfiguration(
String dnsPreresolveHostnames, List<String> dnsFallbackNameservers,
Boolean dnsFilterUnroutableFamilies, boolean enableHttp3, boolean enableHappyEyeballs,
boolean enableInterfaceBinding, int h2ConnectionKeepaliveIdleIntervalMilliseconds,
int h2ConnectionKeepaliveTimeoutSeconds, List<String> h2RawDomains, int maxConnectionsPerHost,
int statsFlushSeconds, int streamIdleTimeoutSeconds, int perTryIdleTimeoutSeconds,
String appVersion, String appId, TrustChainVerification trustChainVerification,
String virtualClusters, List<EnvoyNativeFilterConfig> nativeFilterChain,
int h2ConnectionKeepaliveTimeoutSeconds, boolean h2ExtendKeepaliveTimeout,
List<String> h2RawDomains, int maxConnectionsPerHost, int statsFlushSeconds,
int streamIdleTimeoutSeconds, int perTryIdleTimeoutSeconds, String appVersion, String appId,
TrustChainVerification trustChainVerification, String virtualClusters,
List<EnvoyNativeFilterConfig> nativeFilterChain,
List<EnvoyHTTPFilterFactory> httpPlatformFilterFactories,
Map<String, EnvoyStringAccessor> stringAccessors) {
this.adminInterfaceEnabled = adminInterfaceEnabled;
Expand All @@ -120,6 +124,7 @@ public EnvoyConfiguration(
this.h2ConnectionKeepaliveIdleIntervalMilliseconds =
h2ConnectionKeepaliveIdleIntervalMilliseconds;
this.h2ConnectionKeepaliveTimeoutSeconds = h2ConnectionKeepaliveTimeoutSeconds;
this.h2ExtendKeepaliveTimeout = h2ExtendKeepaliveTimeout;
this.h2RawDomains = h2RawDomains;
this.maxConnectionsPerHost = maxConnectionsPerHost;
this.statsFlushSeconds = statsFlushSeconds;
Expand Down Expand Up @@ -212,6 +217,8 @@ String resolveTemplate(final String configTemplate, final String platformFilterT
enableHappyEyeballs ? "ALL" : "V4_PREFERRED"))
.append(
String.format("- &dns_multiple_addresses %s\n", enableHappyEyeballs ? "true" : "false"))
.append(String.format("- &h2_delay_keepalive_timeout %s\n",
h2ExtendKeepaliveTimeout ? "true" : "false"))
.append("- &dns_resolver_name envoy.network.dns_resolver.cares\n")
.append(String.format("- &dns_refresh_rate %ss\n", dnsRefreshSeconds))
.append(String.format("- &dns_resolver_config %s\n", dnsResolverConfig))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ public class NativeCronetEngineBuilderImpl extends CronetEngineBuilderImpl {
private boolean mEnableInterfaceBinding = false;
private int mH2ConnectionKeepaliveIdleIntervalMilliseconds = 100000000;
private int mH2ConnectionKeepaliveTimeoutSeconds = 10;
private boolean mH2ExtendKeepaliveTimeout = false;
private List<String> mH2RawDomains = Collections.emptyList();
private int mMaxConnectionsPerHost = 7;
private int mStatsFlushSeconds = 60;
Expand Down Expand Up @@ -125,8 +126,9 @@ private EnvoyConfiguration createEnvoyConfiguration() {
mDnsFallbackNameservers, mEnableDnsFilterUnroutableFamilies, mEnableHttp3,
mEnableHappyEyeballs, mEnableInterfaceBinding,
mH2ConnectionKeepaliveIdleIntervalMilliseconds, mH2ConnectionKeepaliveTimeoutSeconds,
mH2RawDomains, mMaxConnectionsPerHost, mStatsFlushSeconds, mStreamIdleTimeoutSeconds,
mPerTryIdleTimeoutSeconds, mAppVersion, mAppId, mTrustChainVerification, mVirtualClusters,
nativeFilterChain, platformFilterChain, stringAccessors);
mH2ExtendKeepaliveTimeout, mH2RawDomains, mMaxConnectionsPerHost, mStatsFlushSeconds,
mStreamIdleTimeoutSeconds, mPerTryIdleTimeoutSeconds, mAppVersion, mAppId,
mTrustChainVerification, mVirtualClusters, nativeFilterChain, platformFilterChain,
stringAccessors);
}
}
14 changes: 14 additions & 0 deletions library/kotlin/io/envoyproxy/envoymobile/EngineBuilder.kt
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ open class EngineBuilder(
private var enableInterfaceBinding = false
private var h2ConnectionKeepaliveIdleIntervalMilliseconds = 100000000
private var h2ConnectionKeepaliveTimeoutSeconds = 10
private var h2ExtendKeepaliveTimeout = false
private var h2RawDomains = listOf<String>()
private var maxConnectionsPerHost = 7
private var statsFlushSeconds = 60
Expand Down Expand Up @@ -262,6 +263,18 @@ open class EngineBuilder(
return this
}

/**
* Extend the keepalive timeout when *any* frame is received on the owning HTTP/2 connection.
*
* @param h2ExtendKeepaliveTimeout whether to extend the keepalive timeout.
*
* @return This builder.
*/
fun h2ExtendKeepaliveTimeout(h2ExtendKeepaliveTimeout: Boolean): EngineBuilder {
Copy link
Contributor

@Augustyniak Augustyniak Apr 29, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ah, one thing that I noticed is that other methods related to h2 ping are named using h2CONNECTIONKeepalive prefix- if you want to add it that's great, if not I think that it's not a big deal as we are going to remove this method at some point anyway (most probably)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah this is already pretty verbose that I'd rather not make it even longer.

this.h2ExtendKeepaliveTimeout = h2ExtendKeepaliveTimeout
return this
}

/**
* Add a list of domains to which h2 connections will be established without protocol negotiation.
*
Expand Down Expand Up @@ -495,6 +508,7 @@ open class EngineBuilder(
enableInterfaceBinding,
h2ConnectionKeepaliveIdleIntervalMilliseconds,
h2ConnectionKeepaliveTimeoutSeconds,
h2ExtendKeepaliveTimeout,
h2RawDomains,
maxConnectionsPerHost,
statsFlushSeconds,
Expand Down
4 changes: 4 additions & 0 deletions library/objective-c/EnvoyConfiguration.m
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ - (instancetype)initWithAdminInterfaceEnabled:(BOOL)adminInterfaceEnabled
h2ConnectionKeepaliveIdleIntervalMilliseconds:
(UInt32)h2ConnectionKeepaliveIdleIntervalMilliseconds
h2ConnectionKeepaliveTimeoutSeconds:(UInt32)h2ConnectionKeepaliveTimeoutSeconds
h2ExtendKeepaliveTimeout:(BOOL)h2ExtendKeepaliveTimeout
h2RawDomains:(NSArray<NSString *> *)h2RawDomains
maxConnectionsPerHost:(UInt32)maxConnectionsPerHost
statsFlushSeconds:(UInt32)statsFlushSeconds
Expand Down Expand Up @@ -56,6 +57,7 @@ - (instancetype)initWithAdminInterfaceEnabled:(BOOL)adminInterfaceEnabled
self.h2ConnectionKeepaliveIdleIntervalMilliseconds =
h2ConnectionKeepaliveIdleIntervalMilliseconds;
self.h2ConnectionKeepaliveTimeoutSeconds = h2ConnectionKeepaliveTimeoutSeconds;
self.h2ExtendKeepaliveTimeout = h2ExtendKeepaliveTimeout;
self.h2RawDomains = h2RawDomains;
self.maxConnectionsPerHost = maxConnectionsPerHost;
self.statsFlushSeconds = statsFlushSeconds;
Expand Down Expand Up @@ -143,6 +145,8 @@ - (nullable NSString *)resolveTemplate:(NSString *)templateYAML {
self.enableHappyEyeballs ? @"ALL" : @"V4_PREFERRED"];
[definitions appendFormat:@"- &dns_multiple_addresses %@\n",
self.enableHappyEyeballs ? @"true" : @"false"];
[definitions appendFormat:@"- &h2_delay_keepalive_timeout %@\n",
self.h2ExtendKeepaliveTimeout ? @"true" : @"false"];
[definitions appendFormat:@"- &dns_refresh_rate %lus\n", (unsigned long)self.dnsRefreshSeconds];
[definitions appendFormat:@"- &dns_resolver_name envoy.network.dns_resolver.apple\n"];
// No additional values are currently needed for Apple-based DNS resolver.
Expand Down
2 changes: 2 additions & 0 deletions library/objective-c/EnvoyEngine.h
Original file line number Diff line number Diff line change
Expand Up @@ -345,6 +345,7 @@ extern const int kEnvoyFilterResumeStatusResumeIteration;
@property (nonatomic, assign) BOOL enforceTrustChainVerification;
@property (nonatomic, assign) UInt32 h2ConnectionKeepaliveIdleIntervalMilliseconds;
@property (nonatomic, assign) UInt32 h2ConnectionKeepaliveTimeoutSeconds;
@property (nonatomic, assign) BOOL h2ExtendKeepaliveTimeout;
@property (nonatomic, strong) NSArray<NSString *> *h2RawDomains;
@property (nonatomic, assign) UInt32 maxConnectionsPerHost;
@property (nonatomic, assign) UInt32 statsFlushSeconds;
Expand Down Expand Up @@ -377,6 +378,7 @@ extern const int kEnvoyFilterResumeStatusResumeIteration;
h2ConnectionKeepaliveIdleIntervalMilliseconds:
(UInt32)h2ConnectionKeepaliveIdleIntervalMilliseconds
h2ConnectionKeepaliveTimeoutSeconds:(UInt32)h2ConnectionKeepaliveTimeoutSeconds
h2ExtendKeepaliveTimeout:(BOOL)h2ExtendKeepaliveTimeout
h2RawDomains:(NSArray<NSString *> *)h2RawDomains
maxConnectionsPerHost:(UInt32)maxConnectionsPerHost
statsFlushSeconds:(UInt32)statsFlushSeconds
Expand Down
13 changes: 13 additions & 0 deletions library/swift/EngineBuilder.swift
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ open class EngineBuilder: NSObject {
private var enforceTrustChainVerification: Bool = true
private var h2ConnectionKeepaliveIdleIntervalMilliseconds: UInt32 = 100000000
private var h2ConnectionKeepaliveTimeoutSeconds: UInt32 = 10
private var h2ExtendKeepaliveTimeout: Bool = false
private var h2RawDomains: [String] = []
private var maxConnectionsPerHost: UInt32 = 7
private var statsFlushSeconds: UInt32 = 60
Expand Down Expand Up @@ -212,6 +213,17 @@ open class EngineBuilder: NSObject {
return self
}

/// Extend the keepalive timeout when *any* frame is received on the owning HTTP/2 connection.
///
/// - parameter h2ExtendKeepaliveTimeout: whether to extend the keepalive timeout.
///
/// - returns: This builder.
@discardableResult
public func h2ExtendKeepaliveTimeout(_ h2ExtendKeepaliveTimeout: Bool) -> Self {
self.h2ExtendKeepaliveTimeout = h2ExtendKeepaliveTimeout
return self
}

/// Add a list of domains to which h2 connections will be established without protocol
/// negotiation.
///
Expand Down Expand Up @@ -433,6 +445,7 @@ open class EngineBuilder: NSObject {
h2ConnectionKeepaliveIdleIntervalMilliseconds:
self.h2ConnectionKeepaliveIdleIntervalMilliseconds,
h2ConnectionKeepaliveTimeoutSeconds: self.h2ConnectionKeepaliveTimeoutSeconds,
h2ExtendKeepaliveTimeout: self.h2ExtendKeepaliveTimeout,
h2RawDomains: self.h2RawDomains,
maxConnectionsPerHost: self.maxConnectionsPerHost,
statsFlushSeconds: self.statsFlushSeconds,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ class EnvoyConfigurationTest {
enableInterfaceBinding: Boolean = false,
h2ConnectionKeepaliveIdleIntervalMilliseconds: Int = 222,
h2ConnectionKeepaliveTimeoutSeconds: Int = 333,
h2ExtendKeepaliveTimeout: Boolean = false,
h2RawDomains: List<String> = listOf("h2-raw.example.com"),
maxConnectionsPerHost: Int = 543,
statsFlushSeconds: Int = 567,
Expand Down Expand Up @@ -77,6 +78,7 @@ class EnvoyConfigurationTest {
enableInterfaceBinding,
h2ConnectionKeepaliveIdleIntervalMilliseconds,
h2ConnectionKeepaliveTimeoutSeconds,
h2ExtendKeepaliveTimeout,
h2RawDomains,
maxConnectionsPerHost,
statsFlushSeconds,
Expand Down Expand Up @@ -161,7 +163,8 @@ class EnvoyConfigurationTest {
enableDnsFilterUnroutableFamilies = true,
enableHappyEyeballs = true,
enableHttp3 = true,
enableInterfaceBinding = true
enableInterfaceBinding = true,
h2ExtendKeepaliveTimeout = true
)

val resolvedTemplate = envoyConfiguration.resolveTemplate(
Expand All @@ -173,6 +176,9 @@ class EnvoyConfigurationTest {
assertThat(resolvedTemplate).contains("&dns_lookup_family ALL")
assertThat(resolvedTemplate).contains("&dns_multiple_addresses true")

// H2
assertThat(resolvedTemplate).contains("&h2_delay_keepalive_timeout true")

// H3
assertThat(resolvedTemplate).contains(APCF_INSERT);

Expand Down
1 change: 1 addition & 0 deletions test/kotlin/apps/experimental/MainActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ class MainActivity : Activity() {
.addPlatformFilter(::BufferDemoFilter)
.addPlatformFilter(::AsyncDemoFilter)
.enableHappyEyeballs(true)
.h2ExtendKeepaliveTimeout(true)
.enableInterfaceBinding(true)
.addNativeFilter("envoy.filters.http.buffer", "{\"@type\":\"type.googleapis.com/envoy.extensions.filters.http.buffer.v3.Buffer\",\"max_request_bytes\":5242880}")
.addStringAccessor("demo-accessor", { "PlatformString" })
Expand Down
10 changes: 10 additions & 0 deletions test/kotlin/io/envoyproxy/envoymobile/EngineBuilderTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,16 @@ class EngineBuilderTest {
assertThat(engine.envoyConfiguration!!.maxConnectionsPerHost).isEqualTo(1234)
}

@Test
fun `enabling h2 keepalive extension overrides default`() {
engineBuilder = EngineBuilder(Standard())
engineBuilder.addEngineType { envoyEngine }
engineBuilder.h2ExtendKeepaliveTimeout(true)

val engine = engineBuilder.build() as EngineImpl
assertThat(engine.envoyConfiguration!!.h2ExtendKeepaliveTimeout).isTrue()
}

@Test
fun `specifying h2 hostnames overrides default`() {
engineBuilder = EngineBuilder(Standard())
Expand Down
21 changes: 20 additions & 1 deletion test/swift/EngineBuilderTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,20 @@ final class EngineBuilderTests: XCTestCase {
self.waitForExpectations(timeout: 0.01)
}

func testAddingH2ExtendKeepaliveTimeoutAddsToConfigurationWhenRunningEnvoy() {
let expectation = self.expectation(description: "Run called with h2ExtendKeepaliveTimeout")
MockEnvoyEngine.onRunWithConfig = { config, _ in
XCTAssertTrue(config.h2ExtendKeepaliveTimeout)
expectation.fulfill()
}

_ = EngineBuilder()
.addEngineType(MockEnvoyEngine.self)
.h2ExtendKeepaliveTimeout(true)
.build()
self.waitForExpectations(timeout: 0.01)
}

func testAddingH2RawDomainsAddsToConfigurationWhenRunningEnvoy() {
let expectation = self.expectation(description: "Run called with expected data")
MockEnvoyEngine.onRunWithConfig = { config, _ in
Expand Down Expand Up @@ -420,6 +434,7 @@ final class EngineBuilderTests: XCTestCase {
enforceTrustChainVerification: false,
h2ConnectionKeepaliveIdleIntervalMilliseconds: 1,
h2ConnectionKeepaliveTimeoutSeconds: 333,
h2ExtendKeepaliveTimeout: true,
h2RawDomains: ["h2-raw.domain"],
maxConnectionsPerHost: 100,
statsFlushSeconds: 600,
Expand Down Expand Up @@ -451,9 +466,10 @@ final class EngineBuilderTests: XCTestCase {
XCTAssertTrue(resolvedYAML.contains("&enable_interface_binding true"))
XCTAssertTrue(resolvedYAML.contains("&trust_chain_verification ACCEPT_UNTRUSTED"))

// HTTP/2
XCTAssertTrue(resolvedYAML.contains("&h2_connection_keepalive_idle_interval 0.001s"))
XCTAssertTrue(resolvedYAML.contains("&h2_connection_keepalive_timeout 333s"))

XCTAssertTrue(resolvedYAML.contains("&h2_delay_keepalive_timeout true"))
XCTAssertTrue(resolvedYAML.contains("&h2_raw_domains [\"h2-raw.domain\"]"))

XCTAssertTrue(resolvedYAML.contains("&max_connections_per_host 100"))
Expand Down Expand Up @@ -496,6 +512,7 @@ final class EngineBuilderTests: XCTestCase {
enforceTrustChainVerification: true,
h2ConnectionKeepaliveIdleIntervalMilliseconds: 1,
h2ConnectionKeepaliveTimeoutSeconds: 333,
h2ExtendKeepaliveTimeout: false,
h2RawDomains: [],
maxConnectionsPerHost: 100,
statsFlushSeconds: 600,
Expand All @@ -519,6 +536,7 @@ final class EngineBuilderTests: XCTestCase {
XCTAssertTrue(resolvedYAML.contains("&dns_multiple_addresses false"))
XCTAssertTrue(resolvedYAML.contains("&enable_interface_binding false"))
XCTAssertTrue(resolvedYAML.contains("&trust_chain_verification VERIFY_TRUST_CHAIN"))
XCTAssertTrue(resolvedYAML.contains("&h2_delay_keepalive_timeout false"))
}

func testReturnsNilWhenUnresolvedValueInTemplate() {
Expand All @@ -537,6 +555,7 @@ final class EngineBuilderTests: XCTestCase {
enforceTrustChainVerification: true,
h2ConnectionKeepaliveIdleIntervalMilliseconds: 222,
h2ConnectionKeepaliveTimeoutSeconds: 333,
h2ExtendKeepaliveTimeout: false,
h2RawDomains: [],
maxConnectionsPerHost: 100,
statsFlushSeconds: 600,
Expand Down
1 change: 1 addition & 0 deletions test/swift/apps/experimental/ViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ final class ViewController: UITableViewController {
.addPlatformFilter(BufferDemoFilter.init)
.addPlatformFilter(AsyncDemoFilter.init)
.enableHappyEyeballs(true)
.h2ExtendKeepaliveTimeout(true)
.enableInterfaceBinding(true)
// swiftlint:disable:next line_length
.addNativeFilter(name: "envoy.filters.http.buffer", typedConfig: "{\"@type\":\"type.googleapis.com/envoy.extensions.filters.http.buffer.v3.Buffer\",\"max_request_bytes\":5242880}")
Expand Down