diff options
author | Cronet Mainline Eng <cronet-mainline-eng+copybara@google.com> | 2023-06-02 09:35:39 -0800 |
---|---|---|
committer | Patrick Rohr <prohr@google.com> | 2023-06-02 11:17:48 -0700 |
commit | d12afe756882b2521faa0b33cbd4813fcea04c22 (patch) | |
tree | 8bc77c24f33342297ce23988de6e6440a5d0a4ce /components/cronet/android | |
parent | 6e619ff2daf1f025aed9c3b67a7492b4b858f981 (diff) | |
download | cronet-d12afe756882b2521faa0b33cbd4813fcea04c22.tar.gz |
Import Cronet version 114.0.5735.84
Project import generated by Copybara.
FolderOrigin-RevId: /tmp/copybara-origin/src
Test: none
Change-Id: Ia00caa61d0c10303bc8a7edf204afc8c1f532064
Diffstat (limited to 'components/cronet/android')
7 files changed, 464 insertions, 296 deletions
diff --git a/components/cronet/android/BUILD.gn b/components/cronet/android/BUILD.gn index 409928e4b..742dd6f29 100644 --- a/components/cronet/android/BUILD.gn +++ b/components/cronet/android/BUILD.gn @@ -250,6 +250,7 @@ android_library("cronet_api_java") { "api/src/org/chromium/net/DnsOptions.java", "api/src/org/chromium/net/ExperimentalBidirectionalStream.java", "api/src/org/chromium/net/ExperimentalCronetEngine.java", + "api/src/org/chromium/net/ExperimentalOptionsTranslatingCronetEngineBuilder.java", "api/src/org/chromium/net/ExperimentalUrlRequest.java", "api/src/org/chromium/net/ICronetEngineBuilder.java", "api/src/org/chromium/net/InlineExecutionProhibitedException.java", diff --git a/components/cronet/android/api/src/org/chromium/net/CronetEngine.java b/components/cronet/android/api/src/org/chromium/net/CronetEngine.java index 4c3dd1729..603915ad6 100644 --- a/components/cronet/android/api/src/org/chromium/net/CronetEngine.java +++ b/components/cronet/android/api/src/org/chromium/net/CronetEngine.java @@ -137,7 +137,13 @@ public abstract class CronetEngine { * <p>{@hide} */ public Builder(ICronetEngineBuilder builderDelegate) { - mBuilderDelegate = builderDelegate; + if (builderDelegate instanceof ExperimentalOptionsTranslatingCronetEngineBuilder) { + // Already wrapped at the top level, no need to do it again + mBuilderDelegate = builderDelegate; + } else { + mBuilderDelegate = + new ExperimentalOptionsTranslatingCronetEngineBuilder(builderDelegate); + } } /** diff --git a/components/cronet/android/api/src/org/chromium/net/ExperimentalCronetEngine.java b/components/cronet/android/api/src/org/chromium/net/ExperimentalCronetEngine.java index 26db9e040..e0bc6e09e 100644 --- a/components/cronet/android/api/src/org/chromium/net/ExperimentalCronetEngine.java +++ b/components/cronet/android/api/src/org/chromium/net/ExperimentalCronetEngine.java @@ -7,18 +7,11 @@ import android.content.Context; import androidx.annotation.VisibleForTesting; -import org.json.JSONException; -import org.json.JSONObject; - -import org.chromium.net.DnsOptions.StaleDnsOptions; - import java.io.IOException; import java.net.Proxy; import java.net.URL; import java.net.URLConnection; -import java.util.ArrayList; import java.util.Date; -import java.util.List; import java.util.Set; import java.util.concurrent.Executor; @@ -96,10 +89,6 @@ public abstract class ExperimentalCronetEngine extends CronetEngine { * Experimental features may be deprecated in the future. Use at your own risk. */ public static class Builder extends CronetEngine.Builder { - private JSONObject mParsedExperimentalOptions; - private final List<ExperimentalOptionsPatch> mExperimentalOptionsPatches = - new ArrayList<>(); - /** * Constructs a {@link Builder} object that facilitates creating a {@link CronetEngine}. The * default configuration enables HTTP/2 and disables QUIC, SDCH and the HTTP cache. @@ -131,11 +120,7 @@ public abstract class ExperimentalCronetEngine extends CronetEngine { * @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; } @@ -185,244 +170,21 @@ public abstract class ExperimentalCronetEngine extends CronetEngine { @Override @QuicOptions.Experimental public Builder setQuicOptions(QuicOptions options) { - // If the delegate builder supports enabling connection migration directly, just use it - if (mBuilderDelegate.getSupportedConfigOptions().contains( - ICronetEngineBuilder.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.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()); - } - }); + 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( - ICronetEngineBuilder.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.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()); - } - }); + 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( - ICronetEngineBuilder.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.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); - } - } - }); - + super.setConnectionMigrationOptions(options); return this; } @@ -470,53 +232,8 @@ public abstract class ExperimentalCronetEngine extends CronetEngine { @Override public ExperimentalCronetEngine 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/org/chromium/net/ExperimentalOptionsTranslatingCronetEngineBuilder.java b/components/cronet/android/api/src/org/chromium/net/ExperimentalOptionsTranslatingCronetEngineBuilder.java new file mode 100644 index 000000000..a363cfcc9 --- /dev/null +++ b/components/cronet/android/api/src/org/chromium/net/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 org.chromium.net; + +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 ICronetEngineBuilder which handles translation of configuration options to + * json-based experimental options, if necessary. + * + * <p>{@hide internal class} + */ +final class ExperimentalOptionsTranslatingCronetEngineBuilder extends ICronetEngineBuilder { + private static final Set<Integer> SUPPORTED_OPTIONS = Collections.unmodifiableSet( + new HashSet(Arrays.asList(ICronetEngineBuilder.CONNECTION_MIGRATION_OPTIONS, + ICronetEngineBuilder.DNS_OPTIONS, ICronetEngineBuilder.QUIC_OPTIONS))); + + private JSONObject mParsedExperimentalOptions; + private final List<ExperimentalOptionsPatch> mExperimentalOptionsPatches = new ArrayList<>(); + + private final ICronetEngineBuilder mDelegate; + + ExperimentalOptionsTranslatingCronetEngineBuilder(ICronetEngineBuilder delegate) { + this.mDelegate = delegate; + } + + @Override + public ICronetEngineBuilder setQuicOptions(QuicOptions options) { + // If the delegate builder supports enabling connection migration directly, just use it + if (mDelegate.getSupportedConfigOptions().contains(ICronetEngineBuilder.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 ICronetEngineBuilder setDnsOptions(DnsOptions options) { + // If the delegate builder supports enabling connection migration directly, just use it + if (mDelegate.getSupportedConfigOptions().contains(ICronetEngineBuilder.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 ICronetEngineBuilder setConnectionMigrationOptions(ConnectionMigrationOptions options) { + // If the delegate builder supports enabling connection migration directly, just use it + if (mDelegate.getSupportedConfigOptions().contains( + ICronetEngineBuilder.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 ICronetEngineBuilder 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 ExperimentalCronetEngine 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 + ICronetEngineBuilder getDelegate() { + return mDelegate; + } + + @FunctionalInterface + private interface ExperimentalOptionsPatch { + void applyTo(JSONObject experimentalOptions) throws JSONException; + } + + // Delegating-only methods + @Override + public ICronetEngineBuilder addPublicKeyPins(String hostName, Set<byte[]> pinsSha256, + boolean includeSubdomains, Date expirationDate) { + mDelegate.addPublicKeyPins(hostName, pinsSha256, includeSubdomains, expirationDate); + return this; + } + + @Override + public ICronetEngineBuilder addQuicHint(String host, int port, int alternatePort) { + mDelegate.addQuicHint(host, port, alternatePort); + return this; + } + + @Override + public ICronetEngineBuilder enableHttp2(boolean value) { + mDelegate.enableHttp2(value); + return this; + } + + @Override + public ICronetEngineBuilder enableHttpCache(int cacheMode, long maxSize) { + mDelegate.enableHttpCache(cacheMode, maxSize); + return this; + } + + @Override + public ICronetEngineBuilder enablePublicKeyPinningBypassForLocalTrustAnchors(boolean value) { + mDelegate.enablePublicKeyPinningBypassForLocalTrustAnchors(value); + return this; + } + + @Override + public ICronetEngineBuilder enableQuic(boolean value) { + mDelegate.enableQuic(value); + return this; + } + + @Override + public ICronetEngineBuilder enableSdch(boolean value) { + mDelegate.enableSdch(value); + return this; + } + + @Override + public ICronetEngineBuilder enableBrotli(boolean value) { + mDelegate.enableBrotli(value); + return this; + } + + @Override + public ICronetEngineBuilder setLibraryLoader(CronetEngine.Builder.LibraryLoader loader) { + mDelegate.setLibraryLoader(loader); + return this; + } + + @Override + public ICronetEngineBuilder setStoragePath(String value) { + mDelegate.setStoragePath(value); + return this; + } + + @Override + public ICronetEngineBuilder setUserAgent(String userAgent) { + mDelegate.setUserAgent(userAgent); + return this; + } + + @Override + public String getDefaultUserAgent() { + return mDelegate.getDefaultUserAgent(); + } + + @Override + public ICronetEngineBuilder enableNetworkQualityEstimator(boolean value) { + mDelegate.enableNetworkQualityEstimator(value); + return this; + } + + @Override + public ICronetEngineBuilder setThreadPriority(int priority) { + mDelegate.setThreadPriority(priority); + return this; + } +} 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 5d58f63bd..31bfa8e47 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 @@ -44,7 +44,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; import org.chromium.net.impl.NativeCronetEngineBuilderImpl; @@ -1483,7 +1482,7 @@ public class CronetUrlRequestContextTest { builder.enablePublicKeyPinningBypassForLocalTrustAnchors(false); CronetUrlRequestContextTestJni.get().verifyUrlRequestContextConfig( CronetUrlRequestContext.createNativeUrlRequestContextConfig( - (CronetEngineBuilderImpl) builder.mBuilderDelegate), + CronetTestUtil.getCronetEngineBuilderImpl(builder)), getTestStorage(getContext())); } @@ -1506,7 +1505,7 @@ public class CronetUrlRequestContextTest { builder.enablePublicKeyPinningBypassForLocalTrustAnchors(false); CronetUrlRequestContextTestJni.get().verifyUrlRequestContextQuicOffConfig( CronetUrlRequestContext.createNativeUrlRequestContextConfig( - (CronetEngineBuilderImpl) builder.mBuilderDelegate), + 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 6f77d0a30..79b33a63c 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 @@ -479,10 +479,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 ExperimentalCronetEngine.Builder(mockBuilderImpl); + testExperimentalOptionsAllSetImpl( + new ExperimentalCronetEngine.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") @@ -555,7 +568,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 6d9c7fbe3..d6a91815c 100644 --- a/components/cronet/android/test/src/org/chromium/net/CronetTestUtil.java +++ b/components/cronet/android/test/src/org/chromium/net/CronetTestUtil.java @@ -94,9 +94,11 @@ public class CronetTestUtil { getCronetEngineBuilderImpl(builder).setMockCertVerifierForTesting(mockCertVerifier); } - public static CronetEngineBuilderImpl getCronetEngineBuilderImpl( + static CronetEngineBuilderImpl getCronetEngineBuilderImpl( ExperimentalCronetEngine.Builder builder) { - return (CronetEngineBuilderImpl) builder.getBuilderDelegate(); + return (CronetEngineBuilderImpl) ((ExperimentalOptionsTranslatingCronetEngineBuilder) + builder.getBuilderDelegate()) + .getDelegate(); } /** |