summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPatrick Rohr <prohr@google.com>2023-06-02 11:51:16 -0700
committerPatrick Rohr <prohr@google.com>2023-06-02 11:51:51 -0700
commit034f8d104a19aeee914aac965a6b784df2c2a2fa (patch)
tree99eb6b11299acf189c460e49519fe877b8631e48
parenta11c5517ad79b6b1a64bdf3caaf8df6cae838426 (diff)
parentd12afe756882b2521faa0b33cbd4813fcea04c22 (diff)
downloadcronet-034f8d104a19aeee914aac965a6b784df2c2a2fa.tar.gz
Merge branch 'upstream-import' into upstream-staging
Test: none Change-Id: Iaf1c6309cec514da486fb3f16085339e7576ea93
-rw-r--r--build/util/LASTCHANGE2
-rw-r--r--build/util/LASTCHANGE.committime2
-rw-r--r--chrome/VERSION2
-rw-r--r--components/cronet/android/BUILD.gn1
-rw-r--r--components/cronet/android/api/src/android/net/http/ExperimentalHttpEngine.java301
-rw-r--r--components/cronet/android/api/src/android/net/http/ExperimentalOptionsTranslatingCronetEngineBuilder.java430
-rw-r--r--components/cronet/android/api/src/android/net/http/HttpEngine.java8
-rw-r--r--components/cronet/android/test/javatests/src/org/chromium/net/CronetUrlRequestContextTest.java5
-rw-r--r--components/cronet/android/test/javatests/src/org/chromium/net/ExperimentalOptionsTest.java19
-rw-r--r--components/cronet/android/test/src/org/chromium/net/CronetTestUtil.java4
10 files changed, 466 insertions, 308 deletions
diff --git a/build/util/LASTCHANGE b/build/util/LASTCHANGE
index f23425f93..a20739da7 100644
--- a/build/util/LASTCHANGE
+++ b/build/util/LASTCHANGE
@@ -1,2 +1,2 @@
-LASTCHANGE=c499d7ea22c8b2dba278465a5df7b86a8efa4e64-refs/branch-heads/5735@{#970}
+LASTCHANGE=8154150933b488112e0d3876e132d1d2b5e54d4b-refs/branch-heads/5735@{#997}
LASTCHANGE_YEAR=2023
diff --git a/build/util/LASTCHANGE.committime b/build/util/LASTCHANGE.committime
index 0e443f24c..f70183f0e 100644
--- a/build/util/LASTCHANGE.committime
+++ b/build/util/LASTCHANGE.committime
@@ -1 +1 @@
-1684896280 \ No newline at end of file
+1684972835 \ No newline at end of file
diff --git a/chrome/VERSION b/chrome/VERSION
index 05ef68145..f8eac5cc2 100644
--- a/chrome/VERSION
+++ b/chrome/VERSION
@@ -1,4 +1,4 @@
MAJOR=114
MINOR=0
BUILD=5735
-PATCH=53
+PATCH=84
diff --git a/components/cronet/android/BUILD.gn b/components/cronet/android/BUILD.gn
index 265dfeb54..3f4c0b51b 100644
--- a/components/cronet/android/BUILD.gn
+++ b/components/cronet/android/BUILD.gn
@@ -247,6 +247,7 @@ android_library("cronet_api_java") {
"api/src/android/net/http/DnsOptions.java",
"api/src/android/net/http/ExperimentalBidirectionalStream.java",
"api/src/android/net/http/ExperimentalHttpEngine.java",
+ "api/src/android/net/http/ExperimentalOptionsTranslatingHttpEngineBuilder.java",
"api/src/android/net/http/ExperimentalUrlRequest.java",
"api/src/android/net/http/HeaderBlock.java",
"api/src/android/net/http/IHttpEngineBuilder.java",
diff --git a/components/cronet/android/api/src/android/net/http/ExperimentalHttpEngine.java b/components/cronet/android/api/src/android/net/http/ExperimentalHttpEngine.java
index f525ad497..c894bce1a 100644
--- a/components/cronet/android/api/src/android/net/http/ExperimentalHttpEngine.java
+++ b/components/cronet/android/api/src/android/net/http/ExperimentalHttpEngine.java
@@ -9,20 +9,14 @@ import static android.net.http.DnsOptions.DNS_OPTION_ENABLED;
import static android.net.http.DnsOptions.DNS_OPTION_UNSPECIFIED;
import android.content.Context;
-import android.net.http.DnsOptions.StaleDnsOptions;
import androidx.annotation.VisibleForTesting;
-import org.json.JSONException;
-import org.json.JSONObject;
-
import java.io.IOException;
import java.net.Proxy;
import java.net.URL;
import java.net.URLConnection;
import java.time.Instant;
-import java.util.ArrayList;
-import java.util.List;
import java.util.Set;
import java.util.concurrent.Executor;
@@ -91,10 +85,6 @@ public abstract class ExperimentalHttpEngine extends HttpEngine {
* Experimental features may be deprecated in the future. Use at your own risk.
*/
public static class Builder extends HttpEngine.Builder {
- private JSONObject mParsedExperimentalOptions;
- private final List<ExperimentalOptionsPatch> mExperimentalOptionsPatches =
- new ArrayList<>();
-
/**
* Constructs a {@link Builder} object that facilitates creating a {@link HttpEngine}. The
* default configuration enables HTTP/2 and disables QUIC, SDCH and the HTTP cache.
@@ -126,11 +116,7 @@ public abstract class ExperimentalHttpEngine extends HttpEngine {
* @return the builder to facilitate chaining.
*/
public Builder setExperimentalOptions(String options) {
- if (options == null || options.isEmpty()) {
- mParsedExperimentalOptions = null;
- } else {
- mParsedExperimentalOptions = parseExperimentalOptions(options);
- }
+ mBuilderDelegate.setExperimentalOptions(options);
return this;
}
@@ -209,255 +195,21 @@ public abstract class ExperimentalHttpEngine extends HttpEngine {
@Override
@QuicOptions.Experimental
public Builder setQuicOptions(QuicOptions options) {
- // If the delegate builder supports enabling connection migration directly, just use it
- if (mBuilderDelegate.getSupportedConfigOptions().contains(
- IHttpEngineBuilder.QUIC_OPTIONS)) {
- mBuilderDelegate.setQuicOptions(options);
- return this;
- }
-
- // If not, we'll have to work around it by modifying the experimental options JSON.
- mExperimentalOptionsPatches.add((experimentalOptions) -> {
- JSONObject quicOptions = createDefaultIfAbsent(experimentalOptions, "QUIC");
-
- // Note: using the experimental APIs always overwrites what's in the experimental
- // JSON, even though "repeated" fields could in theory be additive.
- if (!options.getAllowedQuicHosts().isEmpty()) {
- quicOptions.put(
- "host_whitelist", String.join(",", options.getAllowedQuicHosts()));
- }
- if (!options.getEnabledQuicVersions().isEmpty()) {
- quicOptions.put(
- "quic_version", String.join(",", options.getEnabledQuicVersions()));
- }
- if (!options.getConnectionOptions().isEmpty()) {
- quicOptions.put(
- "connection_options", String.join(",", options.getConnectionOptions()));
- }
- if (!options.getClientConnectionOptions().isEmpty()) {
- quicOptions.put("client_connection_options",
- String.join(",", options.getClientConnectionOptions()));
- }
- if (!options.getExtraQuicheFlags().isEmpty()) {
- quicOptions.put(
- "set_quic_flags", String.join(",", options.getExtraQuicheFlags()));
- }
-
- if (options.hasInMemoryServerConfigsCacheSize()) {
- quicOptions.put("max_server_configs_stored_in_properties",
- options.getInMemoryServerConfigsCacheSize());
- }
-
- if (options.getHandshakeUserAgent() != null) {
- quicOptions.put("user_agent_id", options.getHandshakeUserAgent());
- }
-
- if (options.getRetryWithoutAltSvcOnQuicErrors() != null) {
- quicOptions.put("retry_without_alt_svc_on_quic_errors",
- options.getRetryWithoutAltSvcOnQuicErrors());
- }
-
- if (options.getEnableTlsZeroRtt() != null) {
- quicOptions.put("disable_tls_zero_rtt", !options.getEnableTlsZeroRtt());
- }
-
- if (options.getPreCryptoHandshakeIdleTimeout() != null) {
- quicOptions.put("max_idle_time_before_crypto_handshake_seconds",
- options.getPreCryptoHandshakeIdleTimeout().toSeconds());
- }
-
- if (options.getCryptoHandshakeTimeout() != null) {
- quicOptions.put("max_time_before_crypto_handshake_seconds",
- options.getCryptoHandshakeTimeout().toSeconds());
- }
-
- if (options.getIdleConnectionTimeout() != null) {
- quicOptions.put("idle_connection_timeout_seconds",
- options.getIdleConnectionTimeout().toSeconds());
- }
-
- if (options.getRetransmittableOnWireTimeout() != null) {
- quicOptions.put("retransmittable_on_wire_timeout_milliseconds",
- options.getRetransmittableOnWireTimeout().toMillis());
- }
-
- if (options.getCloseSessionsOnIpChange() != null) {
- quicOptions.put(
- "close_sessions_on_ip_change", options.getCloseSessionsOnIpChange());
- }
-
- if (options.getGoawaySessionsOnIpChange() != null) {
- quicOptions.put(
- "goaway_sessions_on_ip_change", options.getGoawaySessionsOnIpChange());
- }
-
- if (options.getInitialBrokenServicePeriod() != null) {
- quicOptions.put("initial_delay_for_broken_alternative_service_seconds",
- options.getInitialBrokenServicePeriod().toSeconds());
- }
-
- if (options.getIncreaseBrokenServicePeriodExponentially() != null) {
- quicOptions.put("exponential_backoff_on_initial_delay",
- options.getIncreaseBrokenServicePeriodExponentially());
- }
-
- if (options.getDelayJobsWithAvailableSpdySession() != null) {
- quicOptions.put("delay_main_job_with_available_spdy_session",
- options.getDelayJobsWithAvailableSpdySession());
- }
- });
+ super.setQuicOptions(options);
return this;
}
@Override
@DnsOptions.Experimental
public Builder setDnsOptions(DnsOptions options) {
- // If the delegate builder supports enabling connection migration directly, just use it
- if (mBuilderDelegate.getSupportedConfigOptions().contains(
- IHttpEngineBuilder.DNS_OPTIONS)) {
- mBuilderDelegate.setDnsOptions(options);
- return this;
- }
-
- // If not, we'll have to work around it by modifying the experimental options JSON.
- mExperimentalOptionsPatches.add((experimentalOptions) -> {
- JSONObject asyncDnsOptions = createDefaultIfAbsent(experimentalOptions, "AsyncDNS");
-
- if (options.getUseHttpStackDnsResolver() != DNS_OPTION_UNSPECIFIED) {
- asyncDnsOptions.put("enable",
- options.getUseHttpStackDnsResolver() == DNS_OPTION_ENABLED);
- }
-
- JSONObject staleDnsOptions = createDefaultIfAbsent(experimentalOptions, "StaleDNS");
-
- if (options.getStaleDns() != DNS_OPTION_UNSPECIFIED) {
- staleDnsOptions.put("enable",
- options.getStaleDns() == DNS_OPTION_ENABLED);
- }
-
- if (options.getPersistHostCache() != DNS_OPTION_UNSPECIFIED) {
- staleDnsOptions.put("persist_to_disk",
- options.getPersistHostCache() == DNS_OPTION_ENABLED);
- }
-
- if (options.getPersistHostCachePeriod() != null) {
- staleDnsOptions.put(
- "persist_delay_ms", options.getPersistHostCachePeriod().toMillis());
- }
-
- if (options.getStaleDnsOptions() != null) {
- StaleDnsOptions staleDnsOptionsJava = options.getStaleDnsOptions();
-
- if (staleDnsOptionsJava.getAllowCrossNetworkUsage()
- != DNS_OPTION_UNSPECIFIED) {
- staleDnsOptions.put("allow_other_network",
- staleDnsOptionsJava.getAllowCrossNetworkUsage()
- == DNS_OPTION_ENABLED);
- }
-
- if (staleDnsOptionsJava.getFreshLookupTimeout() != null) {
- staleDnsOptions.put(
- "delay_ms", staleDnsOptionsJava.getFreshLookupTimeout().toMillis());
- }
-
- if (staleDnsOptionsJava.getUseStaleOnNameNotResolved()
- != DNS_OPTION_UNSPECIFIED) {
- staleDnsOptions.put("use_stale_on_name_not_resolved",
- staleDnsOptionsJava.getUseStaleOnNameNotResolved()
- == DNS_OPTION_ENABLED);
- }
-
- if (staleDnsOptionsJava.getMaxExpiredDelay() != null) {
- staleDnsOptions.put("max_expired_time_ms",
- staleDnsOptionsJava.getMaxExpiredDelay().toMillis());
- }
- }
-
- JSONObject quicOptions = createDefaultIfAbsent(experimentalOptions, "QUIC");
- if (options.getPreestablishConnectionsToStaleDnsResults()
- != DNS_OPTION_UNSPECIFIED) {
- quicOptions.put("race_stale_dns_on_connection",
- options.getPreestablishConnectionsToStaleDnsResults()
- == DNS_OPTION_ENABLED);
- }
- });
+ super.setDnsOptions(options);
return this;
}
@Override
@ConnectionMigrationOptions.Experimental
public Builder setConnectionMigrationOptions(ConnectionMigrationOptions options) {
- // If the delegate builder supports enabling connection migration directly, just use it
- if (mBuilderDelegate.getSupportedConfigOptions().contains(
- IHttpEngineBuilder.CONNECTION_MIGRATION_OPTIONS)) {
- mBuilderDelegate.setConnectionMigrationOptions(options);
- return this;
- }
-
- // If not, we'll have to work around it by modifying the experimental options JSON.
- mExperimentalOptionsPatches.add((experimentalOptions) -> {
- JSONObject quicOptions = createDefaultIfAbsent(experimentalOptions, "QUIC");
-
- if (options.getDefaultNetworkMigration() != MIGRATION_OPTION_UNSPECIFIED) {
- quicOptions.put("migrate_sessions_on_network_change_v2",
- options.getDefaultNetworkMigration()
- == MIGRATION_OPTION_ENABLED);
- }
- if (options.getAllowServerMigration() != null) {
- quicOptions.put("allow_server_migration", options.getAllowServerMigration());
- }
- if (options.getMigrateIdleConnections() != null) {
- quicOptions.put("migrate_idle_sessions", options.getMigrateIdleConnections());
- }
- if (options.getIdleMigrationPeriod() != null) {
- quicOptions.put("idle_session_migration_period_seconds",
- options.getIdleMigrationPeriod().toSeconds());
- }
- if (options.getMaxTimeOnNonDefaultNetwork() != null) {
- quicOptions.put("max_time_on_non_default_network_seconds",
- options.getMaxTimeOnNonDefaultNetwork().toSeconds());
- }
- if (options.getMaxPathDegradingNonDefaultMigrationsCount() != null) {
- quicOptions.put("max_migrations_to_non_default_network_on_path_degrading",
- options.getMaxPathDegradingNonDefaultMigrationsCount());
- }
- if (options.getMaxWriteErrorNonDefaultNetworkMigrationsCount() != null) {
- quicOptions.put("max_migrations_to_non_default_network_on_write_error",
- options.getMaxWriteErrorNonDefaultNetworkMigrationsCount());
- }
- if (options.getPathDegradationMigration() != MIGRATION_OPTION_UNSPECIFIED) {
- boolean pathDegradationValue = (options.getPathDegradationMigration()
- == MIGRATION_OPTION_ENABLED);
-
- boolean skipPortMigrationFlag = false;
-
- if (options.getAllowNonDefaultNetworkUsage()
- != MIGRATION_OPTION_UNSPECIFIED) {
- boolean nonDefaultNetworkValue =
- (options.getAllowNonDefaultNetworkUsage()
- == MIGRATION_OPTION_ENABLED);
- if (!pathDegradationValue && nonDefaultNetworkValue) {
- // Misconfiguration which doesn't translate easily to the JSON flags
- throw new IllegalArgumentException(
- "Unable to turn on non-default network usage without path "
- + "degradation migration!");
- } else if (pathDegradationValue && nonDefaultNetworkValue) {
- // Both values being true results in the non-default network migration
- // being enabled.
- quicOptions.put("migrate_sessions_early_v2", true);
- quicOptions.put("retry_on_alternate_network_before_handshake", true);
- skipPortMigrationFlag = true;
- } else {
- quicOptions.put("migrate_sessions_early_v2", false);
- }
- }
-
- if (!skipPortMigrationFlag) {
- quicOptions.put("allow_port_migration", pathDegradationValue);
- }
- }
- });
-
+ super.setConnectionMigrationOptions(options);
return this;
}
@@ -488,53 +240,8 @@ public abstract class ExperimentalHttpEngine extends HttpEngine {
@Override
public ExperimentalHttpEngine build() {
- if (mParsedExperimentalOptions == null && mExperimentalOptionsPatches.isEmpty()) {
- return mBuilderDelegate.build();
- }
-
- if (mParsedExperimentalOptions == null) {
- mParsedExperimentalOptions = new JSONObject();
- }
-
- for (ExperimentalOptionsPatch patch : mExperimentalOptionsPatches) {
- try {
- patch.applyTo(mParsedExperimentalOptions);
- } catch (JSONException e) {
- throw new IllegalStateException("Unable to apply JSON patch!", e);
- }
- }
-
- mBuilderDelegate.setExperimentalOptions(mParsedExperimentalOptions.toString());
return mBuilderDelegate.build();
}
-
- private static JSONObject parseExperimentalOptions(String jsonString) {
- try {
- return new JSONObject(jsonString);
- } catch (JSONException e) {
- throw new IllegalArgumentException("Experimental options parsing failed", e);
- }
- }
-
- private static JSONObject createDefaultIfAbsent(JSONObject jsonObject, String key) {
- JSONObject object = jsonObject.optJSONObject(key);
- if (object == null) {
- object = new JSONObject();
- try {
- jsonObject.put(key, object);
- } catch (JSONException e) {
- throw new IllegalArgumentException(
- "Failed adding a default object for key [" + key + "]", e);
- }
- }
-
- return object;
- }
-
- @FunctionalInterface
- private interface ExperimentalOptionsPatch {
- void applyTo(JSONObject experimentalOptions) throws JSONException;
- }
}
@Override
diff --git a/components/cronet/android/api/src/android/net/http/ExperimentalOptionsTranslatingCronetEngineBuilder.java b/components/cronet/android/api/src/android/net/http/ExperimentalOptionsTranslatingCronetEngineBuilder.java
new file mode 100644
index 000000000..6efc222b4
--- /dev/null
+++ b/components/cronet/android/api/src/android/net/http/ExperimentalOptionsTranslatingCronetEngineBuilder.java
@@ -0,0 +1,430 @@
+// Copyright 2016 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+package android.net.http;
+
+import androidx.annotation.VisibleForTesting;
+
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import org.chromium.net.DnsOptions.StaleDnsOptions;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Date;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * An implementation of IHttpEngineBuilder which handles translation of configuration options to
+ * json-based experimental options, if necessary.
+ *
+ * <p>{@hide internal class}
+ */
+final class ExperimentalOptionsTranslatingHttpEngineBuilder extends IHttpEngineBuilder {
+ private static final Set<Integer> SUPPORTED_OPTIONS = Collections.unmodifiableSet(
+ new HashSet(Arrays.asList(IHttpEngineBuilder.CONNECTION_MIGRATION_OPTIONS,
+ IHttpEngineBuilder.DNS_OPTIONS, IHttpEngineBuilder.QUIC_OPTIONS)));
+
+ private JSONObject mParsedExperimentalOptions;
+ private final List<ExperimentalOptionsPatch> mExperimentalOptionsPatches = new ArrayList<>();
+
+ private final IHttpEngineBuilder mDelegate;
+
+ ExperimentalOptionsTranslatingHttpEngineBuilder(IHttpEngineBuilder delegate) {
+ this.mDelegate = delegate;
+ }
+
+ @Override
+ public IHttpEngineBuilder setQuicOptions(QuicOptions options) {
+ // If the delegate builder supports enabling connection migration directly, just use it
+ if (mDelegate.getSupportedConfigOptions().contains(IHttpEngineBuilder.QUIC_OPTIONS)) {
+ mDelegate.setQuicOptions(options);
+ return this;
+ }
+
+ // If not, we'll have to work around it by modifying the experimental options JSON.
+ mExperimentalOptionsPatches.add((experimentalOptions) -> {
+ JSONObject quicOptions = createDefaultIfAbsent(experimentalOptions, "QUIC");
+
+ // Note: using the experimental APIs always overwrites what's in the experimental
+ // JSON, even though "repeated" fields could in theory be additive.
+ if (!options.getQuicHostAllowlist().isEmpty()) {
+ quicOptions.put("host_whitelist", String.join(",", options.getQuicHostAllowlist()));
+ }
+ if (!options.getEnabledQuicVersions().isEmpty()) {
+ quicOptions.put("quic_version", String.join(",", options.getEnabledQuicVersions()));
+ }
+ if (!options.getConnectionOptions().isEmpty()) {
+ quicOptions.put(
+ "connection_options", String.join(",", options.getConnectionOptions()));
+ }
+ if (!options.getClientConnectionOptions().isEmpty()) {
+ quicOptions.put("client_connection_options",
+ String.join(",", options.getClientConnectionOptions()));
+ }
+ if (!options.getExtraQuicheFlags().isEmpty()) {
+ quicOptions.put("set_quic_flags", String.join(",", options.getExtraQuicheFlags()));
+ }
+
+ if (options.getInMemoryServerConfigsCacheSize() != null) {
+ quicOptions.put("max_server_configs_stored_in_properties",
+ options.getInMemoryServerConfigsCacheSize());
+ }
+
+ if (options.getHandshakeUserAgent() != null) {
+ quicOptions.put("user_agent_id", options.getHandshakeUserAgent());
+ }
+
+ if (options.getRetryWithoutAltSvcOnQuicErrors() != null) {
+ quicOptions.put("retry_without_alt_svc_on_quic_errors",
+ options.getRetryWithoutAltSvcOnQuicErrors());
+ }
+
+ if (options.getEnableTlsZeroRtt() != null) {
+ quicOptions.put("disable_tls_zero_rtt", !options.getEnableTlsZeroRtt());
+ }
+
+ if (options.getPreCryptoHandshakeIdleTimeoutSeconds() != null) {
+ quicOptions.put("max_idle_time_before_crypto_handshake_seconds",
+ options.getPreCryptoHandshakeIdleTimeoutSeconds());
+ }
+
+ if (options.getCryptoHandshakeTimeoutSeconds() != null) {
+ quicOptions.put("max_time_before_crypto_handshake_seconds",
+ options.getCryptoHandshakeTimeoutSeconds());
+ }
+
+ if (options.getIdleConnectionTimeoutSeconds() != null) {
+ quicOptions.put("idle_connection_timeout_seconds",
+ options.getIdleConnectionTimeoutSeconds());
+ }
+
+ if (options.getRetransmittableOnWireTimeoutMillis() != null) {
+ quicOptions.put("retransmittable_on_wire_timeout_milliseconds",
+ options.getRetransmittableOnWireTimeoutMillis());
+ }
+
+ if (options.getCloseSessionsOnIpChange() != null) {
+ quicOptions.put(
+ "close_sessions_on_ip_change", options.getCloseSessionsOnIpChange());
+ }
+
+ if (options.getGoawaySessionsOnIpChange() != null) {
+ quicOptions.put(
+ "goaway_sessions_on_ip_change", options.getGoawaySessionsOnIpChange());
+ }
+
+ if (options.getInitialBrokenServicePeriodSeconds() != null) {
+ quicOptions.put("initial_delay_for_broken_alternative_service_seconds",
+ options.getInitialBrokenServicePeriodSeconds());
+ }
+
+ if (options.getIncreaseBrokenServicePeriodExponentially() != null) {
+ quicOptions.put("exponential_backoff_on_initial_delay",
+ options.getIncreaseBrokenServicePeriodExponentially());
+ }
+
+ if (options.getDelayJobsWithAvailableSpdySession() != null) {
+ quicOptions.put("delay_main_job_with_available_spdy_session",
+ options.getDelayJobsWithAvailableSpdySession());
+ }
+ });
+ return this;
+ }
+
+ @Override
+ public IHttpEngineBuilder setDnsOptions(DnsOptions options) {
+ // If the delegate builder supports enabling connection migration directly, just use it
+ if (mDelegate.getSupportedConfigOptions().contains(IHttpEngineBuilder.DNS_OPTIONS)) {
+ mDelegate.setDnsOptions(options);
+ return this;
+ }
+
+ // If not, we'll have to work around it by modifying the experimental options JSON.
+ mExperimentalOptionsPatches.add((experimentalOptions) -> {
+ JSONObject asyncDnsOptions = createDefaultIfAbsent(experimentalOptions, "AsyncDNS");
+
+ if (options.getUseBuiltInDnsResolver() != null) {
+ asyncDnsOptions.put("enable", options.getUseBuiltInDnsResolver());
+ }
+
+ JSONObject staleDnsOptions = createDefaultIfAbsent(experimentalOptions, "StaleDNS");
+
+ if (options.getEnableStaleDns() != null) {
+ staleDnsOptions.put("enable", options.getEnableStaleDns());
+ }
+
+ if (options.getPersistHostCache() != null) {
+ staleDnsOptions.put("persist_to_disk", options.getPersistHostCache());
+ }
+
+ if (options.getPersistHostCachePeriodMillis() != null) {
+ staleDnsOptions.put("persist_delay_ms", options.getPersistHostCachePeriodMillis());
+ }
+
+ if (options.getStaleDnsOptions() != null) {
+ StaleDnsOptions staleDnsOptionsJava = options.getStaleDnsOptions();
+
+ if (staleDnsOptionsJava.getAllowCrossNetworkUsage() != null) {
+ staleDnsOptions.put(
+ "allow_other_network", staleDnsOptionsJava.getAllowCrossNetworkUsage());
+ }
+
+ if (staleDnsOptionsJava.getFreshLookupTimeoutMillis() != null) {
+ staleDnsOptions.put(
+ "delay_ms", staleDnsOptionsJava.getFreshLookupTimeoutMillis());
+ }
+
+ if (staleDnsOptionsJava.getUseStaleOnNameNotResolved() != null) {
+ staleDnsOptions.put("use_stale_on_name_not_resolved",
+ staleDnsOptionsJava.getUseStaleOnNameNotResolved());
+ }
+
+ if (staleDnsOptionsJava.getMaxExpiredDelayMillis() != null) {
+ staleDnsOptions.put(
+ "max_expired_time_ms", staleDnsOptionsJava.getMaxExpiredDelayMillis());
+ }
+ }
+
+ JSONObject quicOptions = createDefaultIfAbsent(experimentalOptions, "QUIC");
+ if (options.getPreestablishConnectionsToStaleDnsResults() != null) {
+ quicOptions.put("race_stale_dns_on_connection",
+ options.getPreestablishConnectionsToStaleDnsResults());
+ }
+ });
+ return this;
+ }
+
+ @Override
+ public IHttpEngineBuilder setConnectionMigrationOptions(ConnectionMigrationOptions options) {
+ // If the delegate builder supports enabling connection migration directly, just use it
+ if (mDelegate.getSupportedConfigOptions().contains(
+ IHttpEngineBuilder.CONNECTION_MIGRATION_OPTIONS)) {
+ mDelegate.setConnectionMigrationOptions(options);
+ return this;
+ }
+
+ // If not, we'll have to work around it by modifying the experimental options JSON.
+ mExperimentalOptionsPatches.add((experimentalOptions) -> {
+ JSONObject quicOptions = createDefaultIfAbsent(experimentalOptions, "QUIC");
+
+ if (options.getEnableDefaultNetworkMigration() != null) {
+ quicOptions.put("migrate_sessions_on_network_change_v2",
+ options.getEnableDefaultNetworkMigration());
+ }
+ if (options.getAllowServerMigration() != null) {
+ quicOptions.put("allow_server_migration", options.getAllowServerMigration());
+ }
+ if (options.getMigrateIdleConnections() != null) {
+ quicOptions.put("migrate_idle_sessions", options.getMigrateIdleConnections());
+ }
+ if (options.getIdleMigrationPeriodSeconds() != null) {
+ quicOptions.put("idle_session_migration_period_seconds",
+ options.getIdleMigrationPeriodSeconds());
+ }
+ if (options.getRetryPreHandshakeErrorsOnAlternateNetwork() != null) {
+ quicOptions.put("retry_on_alternate_network_before_handshake",
+ options.getRetryPreHandshakeErrorsOnAlternateNetwork());
+ }
+ if (options.getMaxTimeOnNonDefaultNetworkSeconds() != null) {
+ quicOptions.put("max_time_on_non_default_network_seconds",
+ options.getMaxTimeOnNonDefaultNetworkSeconds());
+ }
+ if (options.getMaxPathDegradingEagerMigrationsCount() != null) {
+ quicOptions.put("max_migrations_to_non_default_network_on_path_degrading",
+ options.getMaxPathDegradingEagerMigrationsCount());
+ }
+ if (options.getMaxWriteErrorEagerMigrationsCount() != null) {
+ quicOptions.put("max_migrations_to_non_default_network_on_write_error",
+ options.getMaxWriteErrorEagerMigrationsCount());
+ }
+ if (options.getEnablePathDegradationMigration() != null) {
+ boolean pathDegradationValue = options.getEnablePathDegradationMigration();
+
+ boolean skipPortMigrationFlag = false;
+
+ if (options.getAllowNonDefaultNetworkUsage() != null) {
+ boolean nonDefaultNetworkValue = options.getAllowNonDefaultNetworkUsage();
+ if (!pathDegradationValue && nonDefaultNetworkValue) {
+ // Misconfiguration which doesn't translate easily to the JSON flags
+ throw new IllegalArgumentException(
+ "Unable to turn on non-default network usage without path "
+ + "degradation migration!");
+ } else if (pathDegradationValue && nonDefaultNetworkValue) {
+ // Both values being true results in the non-default network migration
+ // being enabled.
+ quicOptions.put("migrate_sessions_early_v2", true);
+ skipPortMigrationFlag = true;
+ } else {
+ quicOptions.put("migrate_sessions_early_v2", false);
+ }
+ }
+
+ if (!skipPortMigrationFlag) {
+ quicOptions.put("allow_port_migration", pathDegradationValue);
+ }
+ }
+ });
+
+ return this;
+ }
+
+ @Override
+ public IHttpEngineBuilder setExperimentalOptions(String options) {
+ if (options == null || options.isEmpty()) {
+ mParsedExperimentalOptions = null;
+ } else {
+ mParsedExperimentalOptions = parseExperimentalOptions(options);
+ }
+ return this;
+ }
+
+ @Override
+ protected Set<Integer> getSupportedConfigOptions() {
+ return SUPPORTED_OPTIONS;
+ }
+
+ @Override
+ public ExperimentalHttpEngine build() {
+ if (mParsedExperimentalOptions == null && mExperimentalOptionsPatches.isEmpty()) {
+ return mDelegate.build();
+ }
+
+ if (mParsedExperimentalOptions == null) {
+ mParsedExperimentalOptions = new JSONObject();
+ }
+
+ for (ExperimentalOptionsPatch patch : mExperimentalOptionsPatches) {
+ try {
+ patch.applyTo(mParsedExperimentalOptions);
+ } catch (JSONException e) {
+ throw new IllegalStateException("Unable to apply JSON patch!", e);
+ }
+ }
+
+ mDelegate.setExperimentalOptions(mParsedExperimentalOptions.toString());
+ return mDelegate.build();
+ }
+
+ private static JSONObject parseExperimentalOptions(String jsonString) {
+ try {
+ return new JSONObject(jsonString);
+ } catch (JSONException e) {
+ throw new IllegalArgumentException("Experimental options parsing failed", e);
+ }
+ }
+
+ private static JSONObject createDefaultIfAbsent(JSONObject jsonObject, String key) {
+ JSONObject object = jsonObject.optJSONObject(key);
+ if (object == null) {
+ object = new JSONObject();
+ try {
+ jsonObject.put(key, object);
+ } catch (JSONException e) {
+ throw new IllegalArgumentException(
+ "Failed adding a default object for key [" + key + "]", e);
+ }
+ }
+
+ return object;
+ }
+
+ @VisibleForTesting
+ IHttpEngineBuilder getDelegate() {
+ return mDelegate;
+ }
+
+ @FunctionalInterface
+ private interface ExperimentalOptionsPatch {
+ void applyTo(JSONObject experimentalOptions) throws JSONException;
+ }
+
+ // Delegating-only methods
+ @Override
+ public IHttpEngineBuilder addPublicKeyPins(String hostName, Set<byte[]> pinsSha256,
+ boolean includeSubdomains, Date expirationDate) {
+ mDelegate.addPublicKeyPins(hostName, pinsSha256, includeSubdomains, expirationDate);
+ return this;
+ }
+
+ @Override
+ public IHttpEngineBuilder addQuicHint(String host, int port, int alternatePort) {
+ mDelegate.addQuicHint(host, port, alternatePort);
+ return this;
+ }
+
+ @Override
+ public IHttpEngineBuilder enableHttp2(boolean value) {
+ mDelegate.enableHttp2(value);
+ return this;
+ }
+
+ @Override
+ public IHttpEngineBuilder enableHttpCache(int cacheMode, long maxSize) {
+ mDelegate.enableHttpCache(cacheMode, maxSize);
+ return this;
+ }
+
+ @Override
+ public IHttpEngineBuilder enablePublicKeyPinningBypassForLocalTrustAnchors(boolean value) {
+ mDelegate.enablePublicKeyPinningBypassForLocalTrustAnchors(value);
+ return this;
+ }
+
+ @Override
+ public IHttpEngineBuilder enableQuic(boolean value) {
+ mDelegate.enableQuic(value);
+ return this;
+ }
+
+ @Override
+ public IHttpEngineBuilder enableSdch(boolean value) {
+ mDelegate.enableSdch(value);
+ return this;
+ }
+
+ @Override
+ public IHttpEngineBuilder enableBrotli(boolean value) {
+ mDelegate.enableBrotli(value);
+ return this;
+ }
+
+ @Override
+ public IHttpEngineBuilder setLibraryLoader(HttpEngine.Builder.LibraryLoader loader) {
+ mDelegate.setLibraryLoader(loader);
+ return this;
+ }
+
+ @Override
+ public IHttpEngineBuilder setStoragePath(String value) {
+ mDelegate.setStoragePath(value);
+ return this;
+ }
+
+ @Override
+ public IHttpEngineBuilder setUserAgent(String userAgent) {
+ mDelegate.setUserAgent(userAgent);
+ return this;
+ }
+
+ @Override
+ public String getDefaultUserAgent() {
+ return mDelegate.getDefaultUserAgent();
+ }
+
+ @Override
+ public IHttpEngineBuilder enableNetworkQualityEstimator(boolean value) {
+ mDelegate.enableNetworkQualityEstimator(value);
+ return this;
+ }
+
+ @Override
+ public IHttpEngineBuilder setThreadPriority(int priority) {
+ mDelegate.setThreadPriority(priority);
+ return this;
+ }
+}
diff --git a/components/cronet/android/api/src/android/net/http/HttpEngine.java b/components/cronet/android/api/src/android/net/http/HttpEngine.java
index 3687180e4..ec3b04c40 100644
--- a/components/cronet/android/api/src/android/net/http/HttpEngine.java
+++ b/components/cronet/android/api/src/android/net/http/HttpEngine.java
@@ -160,7 +160,13 @@ public abstract class HttpEngine {
* {@hide}
*/
Builder(@NonNull IHttpEngineBuilder builderDelegate) {
- mBuilderDelegate = builderDelegate;
+ if (builderDelegate instanceof ExperimentalOptionsTranslatingHttpEngineBuilder) {
+ // Already wrapped at the top level, no need to do it again
+ mBuilderDelegate = builderDelegate;
+ } else {
+ mBuilderDelegate =
+ new ExperimentalOptionsTranslatingHttpEngineBuilder(builderDelegate);
+ }
}
/**
diff --git a/components/cronet/android/test/javatests/src/org/chromium/net/CronetUrlRequestContextTest.java b/components/cronet/android/test/javatests/src/org/chromium/net/CronetUrlRequestContextTest.java
index 80c246482..e48cb8a0c 100644
--- a/components/cronet/android/test/javatests/src/org/chromium/net/CronetUrlRequestContextTest.java
+++ b/components/cronet/android/test/javatests/src/org/chromium/net/CronetUrlRequestContextTest.java
@@ -51,7 +51,6 @@ import org.chromium.net.CronetTestRule.RequiresMinAndroidApi;
import org.chromium.net.CronetTestRule.RequiresMinApi;
import org.chromium.net.NetworkChangeNotifierAutoDetect.ConnectivityManagerDelegate;
import org.chromium.net.TestUrlRequestCallback.ResponseStep;
-import org.chromium.net.impl.CronetEngineBuilderImpl;
import org.chromium.net.impl.CronetLibraryLoader;
import org.chromium.net.impl.CronetUrlRequestContext;
@@ -1482,7 +1481,7 @@ public class CronetUrlRequestContextTest {
builder.setEnablePublicKeyPinningBypassForLocalTrustAnchors(false);
CronetUrlRequestContextTestJni.get().verifyUrlRequestContextConfig(
CronetUrlRequestContext.createNativeUrlRequestContextConfig(
- (CronetEngineBuilderImpl) builder.getBuilderDelegate()),
+ CronetTestUtil.getCronetEngineBuilderImpl(builder)),
getTestStorage(getContext()));
}
@@ -1505,7 +1504,7 @@ public class CronetUrlRequestContextTest {
builder.setEnablePublicKeyPinningBypassForLocalTrustAnchors(false);
CronetUrlRequestContextTestJni.get().verifyUrlRequestContextQuicOffConfig(
CronetUrlRequestContext.createNativeUrlRequestContextConfig(
- (CronetEngineBuilderImpl) builder.getBuilderDelegate()),
+ CronetTestUtil.getCronetEngineBuilderImpl(builder)),
getTestStorage(getContext()));
}
diff --git a/components/cronet/android/test/javatests/src/org/chromium/net/ExperimentalOptionsTest.java b/components/cronet/android/test/javatests/src/org/chromium/net/ExperimentalOptionsTest.java
index 2a78dbd4e..c0f9af289 100644
--- a/components/cronet/android/test/javatests/src/org/chromium/net/ExperimentalOptionsTest.java
+++ b/components/cronet/android/test/javatests/src/org/chromium/net/ExperimentalOptionsTest.java
@@ -511,10 +511,23 @@ public class ExperimentalOptionsTest {
@Test
@MediumTest
@OnlyRunNativeCronet
- public void testExperimentalOptions_allSet() throws Exception {
+ public void testExperimentalOptions_allSet_viaExperimentalEngine() throws Exception {
MockCronetBuilderImpl mockBuilderImpl = MockCronetBuilderImpl.withoutNativeSetterSupport();
- mBuilder = new ExperimentalHttpEngine.Builder(mockBuilderImpl);
+ testExperimentalOptionsAllSetImpl(
+ new ExperimentalHttpEngine.Builder(mockBuilderImpl), mockBuilderImpl);
+ }
+
+ @Test
+ @MediumTest
+ @OnlyRunNativeCronet
+ public void testExperimentalOptions_allSet_viaNonExperimentalEngine() throws Exception {
+ MockCronetBuilderImpl mockBuilderImpl = MockCronetBuilderImpl.withoutNativeSetterSupport();
+ testExperimentalOptionsAllSetImpl(
+ new CronetEngine.Builder(mockBuilderImpl), mockBuilderImpl);
+ }
+ private static void testExperimentalOptionsAllSetImpl(
+ CronetEngine.Builder builder, MockCronetBuilderImpl mockBuilderImpl) throws Exception {
QuicOptions quicOptions =
QuicOptions.builder()
.addAllowedQuicHost("quicHost1.com")
@@ -601,7 +614,7 @@ public class ExperimentalOptionsTest {
toTelephoneKeyboardSequence("badPathErr"))
.build();
- mBuilder.setDnsOptions(dnsOptions)
+ builder.setDnsOptions(dnsOptions)
.setConnectionMigrationOptions(connectionMigrationOptions)
.setQuicOptions(quicOptions)
.build();
diff --git a/components/cronet/android/test/src/org/chromium/net/CronetTestUtil.java b/components/cronet/android/test/src/org/chromium/net/CronetTestUtil.java
index e6954c871..271b02672 100644
--- a/components/cronet/android/test/src/org/chromium/net/CronetTestUtil.java
+++ b/components/cronet/android/test/src/org/chromium/net/CronetTestUtil.java
@@ -99,7 +99,9 @@ public class CronetTestUtil {
public static CronetEngineBuilderImpl getCronetEngineBuilderImpl(
ExperimentalHttpEngine.Builder builder) {
- return (CronetEngineBuilderImpl) builder.getBuilderDelegate();
+ return (CronetEngineBuilderImpl) ((ExperimentalOptionsTranslatingHttpEngineBuilder)
+ builder.getBuilderDelegate())
+ .getDelegate();
}
/**